カーソルのクローズ
運用監視をしていて気がついたのだが、オープンカーソルの数が増えているのだ。
SELECT COUNT(*) FROM V$OPEN_CURSOR;
COUNT(*)
- -
154
ま、まさかカーソルの解放漏れか???
ということで必死こいて調べてみたのだが、さっぱり分からない。
とりあえず問題のSQLを調べてみた。
SELECT
SID, SERIAL#, OSUSER, MACHINE, PROGRAM, USERNAME,SQL_TEXT
FROM
V$OPEN_CURSOR JOIN V$SESSION USING (SID)
WHERE
USERNAME IN ('HOGE');
SQL_TEXTはSQLは全部は出ないのだが、パターンは判明。
ストアドの内部で発行しているSQLのようだ。
ただ、ストアド内部では暗黙カーソルを利用しているのでカーソルの解放漏れが発生するというのは考え難い。
ドライバやTomcatのプーリングか?と思ったけどそんなレポートもどこにもない。
んで、ふと気がついて実験してみた。
こんなストアドを作成する。
SQLA:暗黙カーソルを利用し、重複しない250個のSQLを発行する
つまり
SELECT 1 INTO N FROM DUAL;
SELECT 2 INTO N FROM DUAL;
・・・
SELECT 250 INTO N FROM DUAL;SQLB:SQLAと重複しないさらに250個のSQLを発行する
つまり
SELECT 251 INTO N FROM DUAL;
SELECT 252 INTO N FROM DUAL;
・・・
SELECT 500 INTO N FROM DUAL;SQLC:SQLAともSQLBとも重複しない500個のSQLを発行する
つまり
SELECT 501 INTO N FROM DUAL;
SELECT 502 INTO N FROM DUAL;
・・・
SELECT 1000 INTO N FROM DUAL;
9iではデフォルトのオープンカーソル数は300個である
SHOW PARAMETER open_cursors
NAME TYPE VALUE
- -
open_cursors integer 300
1.を実行したあと、そのセッションで2.を実行したあとの挙動がどうなるのかがポイントだ。
手順
1.現在のオープンカーソル数を調べる('SELECT COUNT(*) FROM V$OPEN_CURSOR;')
2.SQLAを実行
3.オープンカーソル数を調べる
4.SQLBを実行
5.オープンカーソル数を調べる
6.SQLCを実行
7.オープンカーソル数を調べる
結果
1.
COUNT(*)
- -
25
3.
COUNT(*)
- -
276
5.
COUNT(*)
- -
276
7.
COUNT(*)
- -
276
結果にはばらつきがあると思うが、1セッションの中では300個のカーソルを使いまわしている(=同じSQLが実行されれば再利用される?)ことが判明した。
「カーソルのクローズ」とはV$OPEN_CURSORからも消えることだと思っていたのだが、そうではなかったらしい。
コネクションプーリングをしていると、ふと思いついてオープンカーソルを調べて「カーソル解放漏れが!!!」とあわてないようにしよう。
複数セッションからそれぞれ実行すれば、このような結果も戻ってくる。
select count(*) from v$open_cursor;
COUNT(*)
- -
572
'open_cursors'の数はあくまで「1セッションあたり」のオープンカーソル数なので勘違いしてはいけない 壁|▽//)ゝテレテレ
課題
※再利用されるならば、「最大オープンカーソル数を超えました」はどのような場合にでるのだ?
※'open_cursors'を例えば10000とかにしたらパフォーマンスには影響するのか?
=>マニュアルには必要なら増やせ、としか書いてないのでデメリットが不明。
※本当にカーソル解放漏れがあったらどう見分けるのだ?
参考
http://www.atmarkit.co.jp/fdb/rensai/oraobstacle07/oraobstacle07_1.html
http://www.beasys.co.jp/cs/support_news/product_troubleshooting/ORA-1000_Max_Open_Cursors_Pattern.html