問題
特定のタイプのステートメント、特にINSERT ALL
を使用すると、解析時間が指数関数的に増加する場合があります。 。例:
--Clear any cached statements, so we can consistently reproduce the problem.
alter system flush shared_pool;
alter session set sql_trace = true;
--100 rows
INSERT ALL
INTO FileIds(Id,FileTypeGroupId) VALUES(1, 1)
...
repeat 100 times
...
select * from dual;
--500 rows
INSERT ALL
INTO FileIds(Id,FileTypeGroupId) VALUES(1, 1)
...
repeat 500 times
...
select * from dual;
alter session set sql_trace = false;
tkprofを介してトレースファイルを実行すると、多数の行で解析時間が劇的に増加することがわかります。例:
100行:
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.06 0.05 0 1 0 0
Execute 1 0.00 0.00 0 100 303 100
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.06 0.05 0 101 303 100
500行:
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 14.72 14.55 0 0 0 0
Execute 1 0.01 0.02 0 502 1518 500
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 14.74 14.58 0 502 1518 500
ソリューション
- 大きなステートメントをいくつかの小さなステートメントに分割します。最適なサイズを見つけるのは難しいです。 Oracleの一部のバージョンでは、問題の原因となる魔法の数の行があります。私は通常、約100行を使用します。これは、ステートメントのグループ化の利点のほとんどを得るのに十分ですが、解析のバグを回避するのに十分な低さです。または...
-
insert into ... select ... from dual union all ...
を試してください 代わりにメソッド。通常ははるかに高速に実行されますが、解析パフォーマンスもサイズによって大幅に低下する可能性があります。 - Oracleをアップグレードします。新しいバージョンでは、解析パフォーマンスが向上しています。バージョン12.2ではこの問題を再現できなくなりました。
警告
これから間違った教訓を学ばないでください。 SQLのパフォーマンスが心配な場合は、99%の場合、類似したものを分割するのではなく、グループ化する方がよいでしょう。あなたは正しい方法で物事をやっています、あなたはただ奇妙なバグに遭遇しました。 (My Oracle Supportを検索しましたが、これに関する公式のバグは見つかりませんでした。)