0

我必须通过加入一组大表来选择一组值,然后从选定的值中更新另一个大表。我目前遵循以下方法。但我看到了性能缺陷。有哪些替代方法可以完成上述工作?

数据库服务器:Oracle EE

DECLARE
  CURSOR c1
  IS
    SELECT update_data FOR UPDATE OF abc;
BEGIN
  FOR update_data IN c1
  LOOP
    UPDATE klm
    SET klm.xyz  = update_data.cdf
    WHERE update_data.abc = klm.abc;
  END LOOP;
  COMMIT;
END; 
4

2 回答 2

1

很可能简单的更新会执行得更好。

您可以尝试:

update klm t1
set xyz = ( select cdf from update_data t2 where t2.abc = t1.abc ) 
where exists ( select 1 from update_data t2 where t2.abc = t2.abc );

commit;

或者如果可能的话(在 update_data.abc 上有 PK 或唯一索引)

update ( select t1.xyz, t2.cdf from klm t1, update_data t2 where t1.abc = t2.abc ) 
) set xyz = cdf; 

commit;
于 2013-11-05T07:01:34.073 回答
0

如果您在遍历每条记录时遇到性能问题,但表太大而无法进行单次更新,您可以考虑使用 BULK INTO ... LIMIT 和 FORALL 进行批量更新。

CREATE TABLE klm (abc INTEGER, xyz INTEGER);
CREATE TABLE update_data (abc INTEGER, cdf INTEGER);

-- Have pairs of numbers (1000 rows)
INSERT INTO klm SELECT rownum, rownum FROM dual CONNECT BY level <= 1000;
-- Update every second row with 9999
INSERT INTO update_data SELECT rownum * 2, 9999 FROM dual CONNECT BY level <= 500;

DECLARE
  CURSOR c1
  IS
    -- Select the key to be updated and the new value
    SELECT abc, cdf FROM update_data;
  -- Table type and table variable to store rows fetched from the cursor
  TYPE t_update IS TABLE OF c1%rowtype;
  update_tab t_update;
BEGIN
  OPEN c1;
  LOOP
    -- Fetch next 30 rows into update table
    FETCH c1 BULK COLLECT INTO update_tab LIMIT 30;
    -- Exit when there were no more rows fetched
    EXIT WHEN update_tab.count = 0;
    -- This is the key point; uses update_tab to bulk-bind UPDATE statement
    -- and run it for 30 rows in a single context switch
    FORALL i IN 1..update_tab.count
      UPDATE klm
      SET klm.xyz  = update_tab(i).cdf
      WHERE update_tab(i).abc = klm.abc;
    COMMIT;
  END LOOP;
  CLOSE c1;
END;
/

这背后的基本原理是,Oracle 实际上有单独的引擎运行 SQL 语句和 PL/SQL 程序。每当一个过程遇到一条 SQL 语句时,它就会将它交给 SQL 引擎执行。这称为“上下文切换”并且需要大量时间,尤其是在循环中完成时。

批量绑定旨在通过每个 [批量大小] 记录仅执行一次上下文切换来减少这种开销。同样,这肯定不如单个 DML 操作有效,但对于大型表或复杂查询,它可能是最佳可行的解决方案。

我已经使用上述方法更新具有 100M-500M 记录的表,批量大小为 10K-100K,并且效果很好。但是您需要在您的环境中试验批量大小以获得最佳性能。

于 2013-11-05T12:40:25.960 回答