【发布时间】:2020-01-27 14:17:20
【问题描述】:
我有一个 Web 服务 API,它使用项目 ID 列表作为输入参数和数据表作为输出参数(以及与此问题无关的其他参数)。该 API 调用包内的 Oracle 存储过程来获取输出数据表的内容。
存储过程循环遍历每个项目 ID 并为其确定结果。然后它使用一个临时表来存储每个项目 ID(项目 ID、结果、sysdate)的结果。最后,使用游标查询这张临时表并得到结果。
我的问题是,随着时间的推移,这个数据表的内容变得太大(数百万条记录)。我知道我可以进行清理过程,但想知道在创建光标后删除内容是否可以接受。
这是网络服务 API 和存储过程的加水版:
public static EnumGlobal.Errorcode GetOutcomeByItem(string itemIDs, out DataTable dtOutcome, ...)
{
OracleDbContext dbContext = new OracleDbContext();
List<OracleParameter> spParams = new List<OracleParameter>();
DataSet dsOutcome = new DataSet();
...
try
{
spParams.Add(new OracleParameter("IPSITEMIDS", OracleDbType.Varchar2, itemIDs, ParameterDirection.Input));
...
spParams.Add(new OracleParameter("CUR_OUT", OracleDbType.RefCursor, ParameterDirection.Output));
try
{
dbContext.Open();
dbContext.ExecuteStoredProcedure("PKGSOMEQUERY.USPGETOUTCOMEBYITEM", spParams, ref dsOutcome);
}
}
}
PROCEDURE USPGETOUTCOMEBYITEM
(
IPSITEMIDS VARCHAR2,
...
CUR_OUT OUT GETDATACURSOR
)
IS
LVSQUERY VARCHAR2(4000):='';
V_OUTCOME VARCHAR2(5);
V_NEWITEMSLIST VARCHAR2(4000) := REPLACE(IPSITEMIDS, '''', '');
CURSOR cur IS
SELECT REGEXP_SUBSTR(V_NEWITEMSLIST, '[^,]+', 1, LEVEL) V_NEWITEM2 FROM DUAL CONNECT BY instr(V_NEWITEMSLIST, ',',1, LEVEL -1) > 0;
BEGIN
-- Loop thorugh each ITEM ID and determine outcome, add ITEM ID and OUTCOME to temp table
FOR rec IN cur LOOP
V_NEWITEM := rec.V_NEWITEM2;
...
-- Determine V_OUTCOME
...
INSERT INTO TEMPOUTCOME
(
ITEMID,
OUTCOME,
ORIGINDATE
)
VALUES
(
V_NEWITEM,
V_OUTCOME,
SYSDATE
);
COMMIT;
END LOOP;
LVSQUERY:='SELECT ITEMID, OUTCOME, ORIGINDATE FROM TEMPOUTCOME WHERE ITEMID IN (' || IPSITEMIDS || ')';
OPEN CUR_OUT FOR LVSQUERY;
COMMIT;
-- Can I do this?
-- Delete from temp table all item IDs used in this session, in one shot
-- DELETE FROM TEMPOUTCOME WHERE ITEMID IN (select REGEXP_SUBSTR(IPSITEMIDS, '\''(.*?)\''(?:\,)?', 1, LEVEL, NULL, 1) FROM dual CONNECT BY LEVEL <= REGEXP_COUNT(IPSITEMIDS, '''(?: +)?(\,)(?: +)?''', 1) + 1);
EXCEPTION WHEN OTHERS THEN
PKGHANDLEERROR.USPHANDLEERROR('USPGETOUTCOMEBYITEM', LVIERRORCODE);
OPIERRORCODE:=LVIERRORCODE;
END USPGETOUTCOMEBYITEM;
【问题讨论】:
-
您实际上是从
TEMPOUTCOME以外的表中读取的吗?看起来你根本不需要那个临时表。 -
“Determine V_OUTCOME”部分查询一组不同的表以确定每个 ITEMID 的 OUTCOME 是什么。我需要将 ITEMDID-OUTCOME-DATE 记录集发送到调用 API。如果我不使用临时表来存储这些中间结果,我会怎么做?
-
没有看到查询很难说,但我会考虑将这些“确定”查询重写为包含所需值的单个选择,以便可以将选择作为游标返回。
-
我省略的那些查询是一堆选择语句和 IF ... THEN ... ELSE 取决于选择结果,以便设置一些内部变量。最后,确定变量 V_OUCOME。我的问题是在我将光标设置为“SELECT ... from TEMPTOUTCOME”并为 LVSQUERY 变量打开它之后,删除临时表的内容是否安全?
-
光标将包含这些行。但是,这似乎不是解决问题的正确方法。例如,看看这篇文章。 stackoverflow.com/questions/987013/…
标签: c# web-services stored-procedures oracle12c database-cursor