0

大きなテーブルのセットを結合して値のセットを選択し、選択した値から別の大きなテーブルを更新する必要があります。私は現在、以下のアプローチに従っています。しかし、パフォーマンス上の欠点が見られます。上記の種類の作業を行うために利用できる代替方法は何ですか?

DBサーバー:オラクル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

各レコードのループ処理にパフォーマンス上の問題があり、1 回の更新ではテーブルが大きすぎる場合は、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 エンジンに渡して実行します。これは「コンテキストの切り替え」と呼ばれ、特にループで行われる場合、かなりの時間がかかります。

バルク バインディングは、[バルク サイズ] レコードごとに 1 回だけコンテキスト スイッチを実行することで、このオーバーヘッドを削減することを目的としています。繰り返しになりますが、これは確かに単一の DML 操作ほど効果的ではありませんが、大きなテーブルや複雑なクエリの場合は、実行可能な最良のソリューションになる可能性があります。

上記の方法を使用して、バッチサイズが 10K-100K の 100M-500M レコードでテーブルを更新しましたが、うまくいきました。ただし、最高のパフォーマンスを得るには、環境でバッチ サイズを試す必要があります。

于 2013-11-05T12:40:25.960 に答える