PLSQLでテーブルにデータが存在しないことをチェックしてからINSERTを行うという処理を作っていたのですが、MERGEのNOT MATCHEDを使った方が体感的に処理速度が速いなと感じたので処理速度検証をしてみました。
下記サンプルPLSQLで使用しているTB_SAMPLEには200万件データが入っていて、TB_SAMPLE2には100万件データが入っています。
TB_SAMPLEに存在するデータがTB_SAMPLE2に存在しなければ登録するというプログラムになっています。
MERGE処理速度検証
MERGEを使わないサンプルPLSQL
SET SERVEROUTPUT ON SET TIMING ON ---------------------------------------- -- 宣言部 ---------------------------------------- DECLARE -- カーソルの宣言 CURSOR CUR_SAMPLE IS SELECT ID, NAME FROM TB_SAMPLE ORDER BY ID; REC_SAMPLE CUR_SAMPLE%ROWTYPE; WRK_COUNT NUMBER := 0; ---------------------------------------- -- 実行部 ---------------------------------------- BEGIN OPEN CUR_SAMPLE; LOOP FETCH CUR_SAMPLE INTO REC_SAMPLE; EXIT WHEN CUR_SAMPLE%NOTFOUND; -- TB_SAMPLEのIDがTB_SAMPLE2に存在するか確認するために件数を取得 SELECT COUNT(*) INTO WRK_COUNT FROM TB_SAMPLE2 WHERE ID = REC_SAMPLE.ID; -- TB_SAMPLEのIDがTB_SAMPLE2に存在しなければインサート IF WRK_COUNT = 0 THEN INSERT INTO TB_SAMPLE2 (ID, NAME) VALUES(REC_SAMPLE.ID, REC_SAMPLE.NAME); END IF; END LOOP; CLOSE CUR_SAMPLE; END; /
MERGEを使ったサンプルPLSQL
SET SERVEROUTPUT ON SET TIMING ON ---------------------------------------- -- 宣言部 ---------------------------------------- DECLARE -- カーソルの宣言 CURSOR CUR_SAMPLE IS SELECT ID, NAME FROM TB_SAMPLE ORDER BY ID; REC_SAMPLE CUR_SAMPLE%ROWTYPE; ---------------------------------------- -- 実行部 ---------------------------------------- BEGIN OPEN CUR_SAMPLE; LOOP FETCH CUR_SAMPLE INTO REC_SAMPLE; EXIT WHEN CUR_SAMPLE%NOTFOUND; -- TB_SAMPLEのIDがTB_SAMPLE2に存在しない場合、TB_SAMPLEにIDとNAMEを登録する MERGE INTO TB_SAMPLE2 T1 USING ( SELECT REC_SAMPLE.ID AS ID, REC_SAMPLE.NAME AS NAME FROM DUAL) T2 ON (T1.ID = T2.ID) WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (T2.ID, T2.NAME) ; END LOOP; CLOSE CUR_SAMPLE; END; /
処理速度結果
回数/平均 | MERGEを使わないサンプルPLSQL | MERGEを使ったサンプルPLSQL |
---|---|---|
1回目 | 67秒 | 58秒 |
2回目 | 68秒 | 59秒 |
3回目 | 68秒 | 58秒 |
平均 | 67秒 | 58秒 |
MERGEを使った方が9秒早いという結果になりました。
現場で扱うテーブルはカラムの数やデータ件数がサンプルPLSQLよりもさらに多いいと思いますので、この処理速度結果の差はもっと大きくなると思います。なので、積極的にMERGEのNOT MATCHEDを使うことを推奨します。