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を使うことを推奨します。