oracle 通过游标进行更新需要花费大量时间

k97glaaz  于 2023-08-03  发布在  Oracle
关注(0)|答案(2)|浏览(129)

我通过获取addr_id并在两个表(同一个表和另一个表)中为不同的列更新它来执行地址关联。然而,即使我使用平行度为500的平行提示,也需要花费大量时间。你能在这里帮忙吗?下面是程序。

PROCEDURE 
ADD_ASOC AS
BEGIN
DECLARE
CURSOR C1 IS
SELECT /*+ PARALLEL(500) */ ADDR_ID FROM TEMP_ADDR WHERE BATCH_RANGE BETWEEN 100 AND 900;

TYPE CURSOR_ATT IS TABLE OF C1%ROWTYPE;

L_CURSOR CURSOR_ATT;

    BEGIN
    OPEN C1;
    LOOP

    FETCH C1 BULK COLLECT INTO          L_CURSOR LIMIT 5000;
EXIT WHEN L_CURSOR.COUNT = 0;

FOR I IN 1 .. L_CURSOR.COUNT LOOP

UPDATE  /*+ PARALLEL(500) */ MAIN_ADDR SET ADR_NAME = L_CURSOR(I).ADDR_ID||'RESIDENCE'
WHERE ADDR_ID = L_CURSOR(I).ADDR_ID;


UPDATE  /*+ PARALLEL(500) */ TEMP_ADDR SET ADR_NAME = L_CURSOR(I).ADDR_ID||'RESIDENCE'

WHERE ADDR_ID = L_CURSOR(I).ADDR_ID
AND BATCH_RANGE BETWEEN 100 AND 900;

COMMIT;
END LOOP;
END LOOP;
COMMIT;
CLOSE C1;
END;
COMMIT;

字符串
我使用平行度为500执行,但无效。

jaql4c8m

jaql4c8m1#

您似乎不需要游标或循环,并且可以使用MERGE语句和UPDATE语句

PROCEDURE ADD_ASOC
AS
BEGIN
  MERGE INTO MAIN_ADDR m
  USING TEMP_ADDR t
  ON ( m.addr_id = t.addr_id AND t.BATCH_RANGE BETWEEN 100 AND 900)
  WHEN MATCHED THEN;
    UPDATE
    SET ADR_NAME = t.ADDR_ID||'RESIDENCE';

  UPDATE TEMP_ADDR
  SET ADR_NAME = ADDR_ID||'RESIDENCE'
  WHERE BATCH_RANGE BETWEEN 100 AND 900;
END;

字符串

  • 注意:如果您在一个过程中COMMIT,那么您不能使用多个过程,然后如果最后一个失败,请选择ROLLBACK全部。相反,您应该从过程中删除COMMIT,并从调用过程的会话中调用COMMIT,然后您将能够将多个过程链接在一起。(另外,重复使用COMMIT非常慢。
slhcrj9b

slhcrj9b2#

  • 在单行update语句上的parallel提示充其量是无意义的。
  • commit非常昂贵。在循环的每一次迭代上执行commit将非常慢。
  • 执行forall比执行for循环更高效。在单个SQL语句中执行更新是最有效的方法。
  • 您是如何得出select语句的并行度为500的?这似乎是非常非常不可能的,这是一个合理的数字。

除此之外,你做了什么来跟踪你的代码,或者看看是什么花了时间。我们当然可以猜测可能会很慢的事情,但是我们没有办法看到,例如,你的一个表是否缺少addr_id上的索引,或者是否有一堆未索引的外键需要管理,或者是否有触发器使事情变慢。
forall方法会更快(不如单个update语句快,但比循环中的逐行处理更好)。

FORALL I IN 1 .. L_CURSOR.COUNT
  UPDATE MAIN_ADDR 
     SET ADR_NAME = L_CURSOR(I).ADDR_ID||'RESIDENCE'
   WHERE ADDR_ID = L_CURSOR(I).ADDR_ID;

FORALL I IN 1 .. L_CURSOR.COUNT
  UPDATE TEMP_ADDR 
     SET ADR_NAME = L_CURSOR(I).ADDR_ID||'RESIDENCE'
   WHERE ADDR_ID = L_CURSOR(I).ADDR_ID
     AND BATCH_RANGE BETWEEN 100 AND 900;

字符串
UPDATE /+ PARALLEL(500)/ TEMP_ADDR SET ADR_NAME = L_CURSOR(I).ADDR_ID||“住宅”
其中ADDR_ID = L_CURSOR(I).ADDR_ID和BATCH_RANGE在100和900之间;

相关问题