MERGE文を使用して高速一括更新(Oracle)
※注意 速度の話をしていますが、体感速度で話をしており、実速度は計っていません。
Oracle9i以降対応のお話です。
お仕事でSQL(PL/SQL)のチューニングを行った際のお話です。
備忘録的な感じでメモ。
お仕事で、下記の様なSQL文とPL/SQL文で書かれた
速度がすごく遅い処理に出会いました。
UPDATE TBL1 A SET A.XXX = ( SELECT subA.ZZZ AS ZZZ FROM TBL2 subA WHERE subA.ID = A.ID )
DECLARE CURSOR C IS SELECT B.ID AS ID ,B.ZZZ AS ZZZ FROM TBL2 B BEGIN FOR R IN C LOOP UPDATE TBL1 A SET A.XXX = R.ZZZ WHERE A.ID = R.ID; END LOOP; COMMIT; END;
前者は副問合せを使用しているので
「きっとSELECT文の箇所が複数回呼ばれているから遅そうだな」と、
後者は「TBL2のデータ分だけループをグルグル回しているので遅そうだな」
ということが感じとれますね。
「後者はバルク処理を使えば多少マシになるんじゃね?」とかは要らないです。
これらの一括更新処理をはやく行うためには、MERGE文を使うと良いです。
どういう風に書き換えるのかは、下記の通り。
MERGE INTO TBL1 A USING ( SELECT subA.ID AS ID ,subA.ZZZ AS ZZZ FROM TBL2 subA ) B ON (A.ID = B.ID) WHEN MATCHED THEN UPDATE SET A.XXX = B.ZZZ
このソースコードを読んで、
「アレ?WHEN NOT MATCHED THENまで書いてないけど大丈夫?」
と思われたかもしれませんが、問題ありません。
ちゃんと動きますので、ご安心を。
最後に。
SELECT INSERTを最初に行うなら、後で一括更新を行わず、
その時に表を結合して一気にINSERTしてしまったほうが良い気がしますね。
(チューニングを行った処理は、SELECT INSERT後一括更新を掛けていた。)