[Oracle] ORA-01000エラーの回避方法 | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

大量のデータを処理した場合などに

ORA-01000 最大オープン・カーソル数を超えました。


というエラーが発生することがあります。


これは文字通り一度にオープンできるカーソルの最大数を超えたことを示すエラーです。



Oracleで同時にオープンできるカーソルの最大数は初期化パラメータOPEN_CURSORSで設定することができます。


では増やせばいいじゃないかと安易に考えてしまいがちですが、そう易々と解決できるものではありません。


OPEN_CURSORSの値を増やせば、確かに上記のエラーが発生する確率を減らすことはできますが、逆にリソースを多く消費するようになり、Oracleのパフォーマンスが全体的に低下してしまうからです。

そもそもカーソルというもの自体リソースを多く消費するものなので、大量に使用するというのはアプリケーションの仕組み的に好ましくありません。


ですから、上記のエラーを回避するにはOPEN_CURSORSの値を増やすよりも、むしろアプリケーションで必要以上にカーソルを使用するようなロジックになっていないかどうかをまず見直すことのほうが大事です。



例えば、JDBCを使用したJavaアプリケーションの場合、Statementなどでカーソルが暗黙的に使用されています。


ということは大量のStatementが開きっぱなしになっているような状況があれば、そこで上記のエラーを引き起こす可能性があるのです。


実際に簡単にテストしてみたところ、以下のようなことをすると大量のカーソルを開いてしまうようです。


for ( int i = 1; i <= 10000; i++ ) {
  CallableStatement cstmt = 
    con.prepareCall( "{ call insert into emp (empno, ename ) VALUES ( ?,? ) }" );
  cstmt.setInt( 1 , i );
  cstmt.setString( 2 , "Test" + i );
  cstmt.execute();
}


forループを使ってデータを10000件登録するという処理ですが、データを1件登録(cstmt.execute())した後、そのステートメントをクローズ(cstmt.close())せずに新しいステートメントを生成しています。


このような処理を行うと、前のステートメントはオープンした状態で残ってしまい、処理が進むにしたがってその数も増えてしまうのです。


当然、データベース上でオープンされているカーソルも同じ数だけ増えることになり、上記のエラーを引き起こすということになるわけです。

このプログラムの場合、次のステートメントを生成する前に、前のステートメントをクローズすると前のステートメントでオープンされたカーソルもクローズされるので、上記のエラーは発生しなくなります。


が、そもそもステートメントを何回も生成すること自体、パフォーマンス悪化の要因になりますので、forループの中で1件ごとにステートメントを生成するのではなく、ループに入る前にステートメントを生成しておき、パラメータを置き換えて繰り返し実行するという方法のほうがいいでしょう。



もちろん、どんなプログラミング言語を使う場合でもそうですが、”開けたら、閉めろ...”を徹底することがこういったトラブルを防ぐ近道でしょう。




【関連エントリ】
[Oracle] ORA-01000エラーの回避方法 2004/07/04
[Oracle] ORA-01000エラーの原因特定のためにV$OPEN_CURSORを利用する 2006/10/03