[JavaScript, Database] Node-oracledb: Avoiding "ORA-01000: maximum open cursors exceeded"

原文はこちら。
https://blogs.oracle.com/opal/entry/node_oracledb_avoiding_ora_01000

Nodeを始めた開発者は、もっとも予期しないタイミングでメソッドが呼び出されるように見えるという、異なるJavaScriptのプログラミングスタイルに直面する羽目になるでしょう。最初のnode-oracledbでハックするフェーズにいる間に、
ORA-01000(maximum open cursors exceeded / 最大オープン・カーソル数を超えました
というエラーに出くわすことがあるでしょう。カーソルとは「解析済みSQL分とその他の処理情報を保持するセッション固有のプライベートSQL領域へのハンドル」です。

ORA-01000に出くわしたときに実施すべきことをまとめました。
  • 一度に大量の不完全に処理されたステートメントをオープンしない
    • 接続をリリースする前にResultSetをクローズする
    • PL/SQLブロック内でdbms_sql.open_cursor()を使ってカーソルをオープンする場合、REF CURSORSをnode-oracledbへ返す場合以外は、PL/SQLブロックから返る前にクローズする。(将来のnode-oracledbバージョンでOracle Database 12cのImplicit Result Setをサポートする場合、これらのカーソルもまたPL/SQLブロック内で閉じてはいけない)
    • アプリケーションが想定通りの順番で接続とステートメントを処理していることを確認する
  • 適切なステートメントキャッシュサイズ(Statement Cache size)を選択する。node-oracledbには接続ごとのステートメントキャッシュがある。node-oracledbが内部でステートメントをリリースすると、当該接続のステートメントキャッシュに入れられるが、ステートメントの再実行を非常に効率的にするため、カーソルは引き続きオープンしたままである。
    キャッシュサイズはstmtCacheSizeという属性で設定することができる。
    stmtCacheSize
    https://github.com/oracle/node-oracledb/blob/master/doc/api.md#propdbstmtcachesize
    適切なステートメントキャッシュサイズはステートメントの局所性に関する知識とアプリケーションで利用可能なリソースに依存する。ステートメントを再実行する場合、実行されていればキャッシュにステートメントが残っている。何個のステートメントをキャッシュに保持したいか、ステートメントを再実行しないとか、キャッシュにないというまれなケースでは、キャッシュを無効にして管理のオーバヘッドを排除することができる。
    誤ったステートメントキャッシュサイズを設定すると、アプリケーションの効率が低下する。幸いにしてOracle 12.1では、oraaccess.xmlファイルを使い、キャッシュを自動的にチューニングすることができる。
    External Configuration
    https://github.com/oracle/node-oracledb/blob/master/doc/api.md#oraaccess
    node-oracledbのステートメントキャッシュに関する詳細情報は以下のリンクに記載がある。
    Statement Caching
    https://github.com/oracle/node-oracledb/blob/master/doc/api.md#stmtcache
  • バインド変数を利用することを忘れないこと。使わない場合、ステートメントの各バリアントが独自のステートメントキャッシュエントリとカーソルを持つ。適切なバインディングを使えば、一個のエントリとカーソルだけですむ。
  • 適切にデータベースのopen_cursorsパラメータを設定する。このパラメータは各セッション(つまり、node-oracleの各接続)が利用可能なカーソルの最大個数を指定するもので、接続数がこの値を上回ると、ORA-01000がスローされる。以下のドキュメントにopen_cursorsの記載がある。
    Oracle® Databaseリファレンス 12cリリース1 (12.1)
    http://docs.oracle.com/cd/E57425_01/121/REFRN/GUID-FAFD1247-06E5-4E64-917F-AEBD4703CF40.htm
    Oracle® Database Reference 12c Release 1 (12.1)
    http://docs.oracle.com/database/121/REFRN/GUID-FAFD1247-06E5-4E64-917F-AEBD4703CF40.htm
    接続のステートメント・キャッシュ内のエントリごとのカーソルと一緒に、接続が現在実行している新しいステートメント、もしくはリリースされていないResultSetもまたカーソルを消費する(どちらの状況では、まだキャッシュされていない)。任意の接続が持つオープンされたカーソルの個数の最大値を収容できるよう、OPEN_CURSORSは十分に大きな数値になっていることを確認すること。必要な上限値は、stmtCacheSize + 接続中のステートメントの最大実行回数である。
    これは、すべての接続単位であることを忘れてはいけない。ステートメントが内部的にリリースされた場合も、キャッシュ管理が行われる。接続の大部分がOPEN_CURSORSで定義した個数よりも少ないカーソルを使用できるが、一つの接続でリミットに達して、新規のステートメントを実行しようとすると、その接続でORA-01000を取得することになる。

0 件のコメント:

コメントを投稿