こんにちは、石川さんです。
最近ORACLEのPL/SQLでストアドプログラムを作っています。どっちのパフォーマンスが良いのか、ちょっと気になったので調べてみました。
作っていたのは、ファイルを1行ずつ読み込んで、諸々チェックして、問題なければテーブルにINSERTする、というよくある単純な処理です。このとき、呼び出し側からOUTパラメータを指定して、登録件数とチェックしたエラー件数をもどす、という要件があるときの変数の使い方として、以下の二通りを考えました。どっちが早いのでしょうね?
- OUTパラメータを直接インクリメントする
- 別途定義したローカル変数をインクリメントして、最後にOUTパラメータへ結果をセットする
実験
わからないことは、すぐに実験しましょう。と、いうことで以下のスクリプトを作ってみました。
set serveroutput on
DECLARE
counter NUMBER := 0;
s1 TIMESTAMP;
s2 TIMESTAMP;
e1 TIMESTAMP;
e2 TIMESTAMP;
PROCEDURE inner_procedure1(an_counter OUT NUMBER) IS
BEGIN
an_counter := 0;
LOOP
an_counter := an_counter + 1;
EXIT WHEN an_counter > 10000000;
END LOOP;
END;
PROCEDURE inner_procedure2(an_counter OUT NUMBER) IS
counter NUMBER := 0;
BEGIN
an_counter := 0;
LOOP
counter := counter + 1;
EXIT WHEN counter > 10000000;
END LOOP;
an_counter := counter;
END;
BEGIN
s1 := SYSTIMESTAMP;
inner_procedure1(counter);
e1 := SYSTIMESTAMP;
s2 := SYSTIMESTAMP;
inner_procedure2(counter);
e2 := SYSTIMESTAMP;
DBMS_OUTPUT.PUT_LINE('START:'||TO_CHAR(s1,'YYYY-MM-DD HH24:MI:SS.FF'));
DBMS_OUTPUT.PUT_LINE('END :'||TO_CHAR(e1,'YYYY-MM-DD HH24:MI:SS.FF'));
DBMS_OUTPUT.PUT_LINE(e1 - s1);
DBMS_OUTPUT.PUT_LINE('START:'||TO_CHAR(s2,'YYYY-MM-DD HH24:MI:SS.FF'));
DBMS_OUTPUT.PUT_LINE('END :'||TO_CHAR(e2,'YYYY-MM-DD HH24:MI:SS.FF'));
DBMS_OUTPUT.PUT_LINE(e2 - s2);
END;
/
inner_procedure1が、OUTパラメータをインクリメントする「1.」のケースで、inner_procedure2が、ローカル変数をインクリメントする「2.」のケースになります。
では何回か実行します。そして、結果は、、、
(・・・略・・・) 12:41:11 39 / START:2022-11-30 12:41:11.901000000 END :2022-11-30 12:41:12.665000000 +000000000 00:00:00.764000000 START:2022-11-30 12:41:12.665000000 END :2022-11-30 12:41:13.149000000 +000000000 00:00:00.484000000 PL/SQLプロシージャが正常に完了しました。 経過: 00:00:01.26 12:41:13 SQL> / START:2022-11-30 12:41:18.841000000 END :2022-11-30 12:41:19.492000000 +000000000 00:00:00.651000000 START:2022-11-30 12:41:19.492000000 END :2022-11-30 12:41:19.872000000 +000000000 00:00:00.380000000 PL/SQLプロシージャが正常に完了しました。 経過: 00:00:01.03 12:41:19 SQL> / START:2022-11-30 12:41:23.800000000 END :2022-11-30 12:41:24.439000000 +000000000 00:00:00.639000000 START:2022-11-30 12:41:24.439000000 END :2022-11-30 12:41:24.818000000 +000000000 00:00:00.379000000 PL/SQLプロシージャが正常に完了しました。 経過: 00:00:01.02 12:41:24 SQL>
「2.ローカル変数をインクリメントして、最後にOUTパラメータへ結果をセットする」方がおよそ1.5倍ほど、はやい!ということがわかりました。
と、いうことで今後はOUTパラメータへのアクセスは最後の一回のみ、ということにしたいと思います。
結論
ローカル変数をインクリメントして、最後にOUTパラメータへ結果をセットした方がはやい、というのは結果からみるとそのとおりなのですが、実は、10000000回(1千万回)ループしているのですよね。その上で、早くなったのは、0.3秒未満なので、大量データを何度も扱わない限りは気にしなくても良さそうです。億超えのデータをしょっちゅう扱うような人は、ちょっとずつ効いてきますので、気にしましょう!
ぼくはとっても気になります!!!

