これは Oracle の障害ではなく、TOAD が SQL を Oracle に送信する方法にすぎません。つまり、toad はステートメント ハンドルを oracle にキャッシュせず、完了時にクローズするだけです。
Oracle は、クエリが SQL エンジンに送信されるときに、クエリに対して 3 つの主な処理のいずれかを行います。
- ハードパース
- ソフトパース
- 解析しない
つまり、ケース 3 になりたいのですが、ケース 1 にはなりたくありません。では、それぞれのケースはいつ発生するのでしょうか。
SQL が共有プールにまったくない場合、または SQL が共有プールにあるが、使用中のバインド変数/リテラルが現在の SQL を使用できないことを意味する場合、ハード解析が発生します。たとえば、この SQL を 3 回発行したとしますselect MY_SEQUENCE_SEQ.nextval from dual
。これは、Oracle がこの SQL を初めて認識して共有プールに入れるときにハード解析し、2 回目と 3 回目の呼び出しでソフト解析します。これは簡単にわかります。
SQL> select n.name, s.value from v$mystat s, v$statname n where n.statistic# = s.statistic# and n.name in ('parse count (hard)', 'parse count (total)');
NAME VALUE
-------------------- ----------
parse count (total) 522
parse count (hard) 287
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
62
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
63
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
64
SQL> select n.name, s.value from v$mystat s, v$statname n where n.statistic# = s.statistic# and n.name in ('parse count (hard)', 'parse count (total)');
NAME VALUE
-------------------- ----------
parse count (total) 526
parse count (hard) 288
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select /* test1 */%';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select /* test1 */ MY_SEQUENCE 3 3
_SEQ.nextval from dual
ハード解析が 1 つ増え、SQL は 3 つの解析を登録したため、1 つのハード解析 (共有プールに入れるため) と 2 つのソフト解析が行われます。
なぜソフト解析したのですか?「解析なし」が発生するためには、クライアント コードがステートメント ハンドルを保持し、それを再実行する必要があります。つまり、これを Java で書く場合は、次のように書きます。
public static int getNextSeq(String str)
throws Exception
{
if (sel == null)
{
sel = con.prepareStatement("select MY_SEQUENCE_SEQ.nextval v from dual "+str);
}
ResultSet rs = sel.executeQuery();
int seqVal=0;
while (rs.next())
{
seqVal = rs.getInt("V");
}
return seqVal;
}
つまり、まだ行っていない場合にのみ、PrepareStatement を呼び出します。このコードを実行すると
System.out.println(getNextSeq(args[0]));
System.out.println(getNextSeq(args[0]));
System.out.println(getNextSeq(args[0]));
これを実際に見ることができます:
SQL> host java Prep two
70
71
72
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select %two';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select MY_SEQUENCE_SEQ.nextval 3 1
v from dual two
現在、オラクルは1つのハード解析を除いてSQLを解析しませんでした。Java コードの書き方が不適切だった場合、次のようになります。
sel = con.prepareStatement("select MY_SEQUENCE_SEQ.nextval v from dual "+str);
ResultSet rs = sel.executeQuery();
SQL> host java Prep three
73
74
75
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select %three';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select MY_SEQUENCE_SEQ.nextval 3 3
v from dual three
これで、解析カウント = 実行数が表示されます。言い換えれば、理想的ではない各呼び出しをソフト解析しています。繰り返しますが、Oracleの制限ではなく、クライアントの実装が不十分です。
PL/SQL では、これについて心配する必要はありません。なんで?PL/SQL は、SQL を実行するために最適化されているため (驚くべきことではありません!)、どちらも解析しません。例えば:
SQL> declare
2 v_seq number;
3 begin
4 for idx in 1..3 loop
5 select MY_SEQUENCE_SEQ.nextval into v_seq from dual pls_test;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'SELECT %PLS_TEST';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
SELECT MY_SEQUENCE_SEQ.NEXTVAL 3 1
FROM DUAL PLS_TEST
ここで、pl/sql がこの最適化を行う際の注意事項が 1 つあります。それは、パラメータ SESSION_CACHED_CURSORS です。特定のセッションで、Oracle は一連のカーソルを開いたままにします (つまり、それらはソフト オープンであり、さらにカーソルが必要な場合は閉じます)。したがって、SESSION_CACHED_CURSORS=0 を指定して上記のテストを繰り返すと、ソフト解析が突然クリープするのが見られます。
SQL> alter session set session_cached_cursors=0;
Session altered.
SQL> declare
2 v_seq number;
3 begin
4 for idx in 1..3 loop
5 select MY_SEQUENCE_SEQ.nextval into v_seq from dual pls_test2;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'SELECT %PLS_TEST2';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
SELECT MY_SEQUENCE_SEQ.NEXTVAL 3 3
FROM DUAL PLS_TEST2
明らかに、キャッシュされたカーソルの値が高いほど、ソフト解析を回避し、完全な解析を回避するという聖杯に到達する必要がある可能性が高くなります。