初期化パラメータCURSOR_SHARINGを'FORCE'または'SIMILAR'にすると、リテラルのみが異なるSQLを自動的にバインド変数化し、SQLを共有してくれます。
しかし、これは便利と思ってテスト環境で使っていたら、あるプログラムで
ORA-01008: バインドされていない変数があります。
というエラーが発生しました。
CURSOR_SHARING=EXACT(デフォルト)に戻すと発生しなくなったため、どうもCURSOR_SHARINGに起因するバグのようです。
こんなもん、恐くて使えんじゃないか!
上記のエラーが発生したのはWindows版のOracle9.2.0.6で、以下のように動的SQLを使ってプロシージャを実行している部分です。
DECLARE wk_sql VARCHAR2(4000); BEGIN wk_sql := 'CALL DBMS_STATS.GATHER_TABLE_STATS(''SCOTT'',''EMP'')'; EXECUTE IMMEDIATE wk_sql; END; / DECLARE * 行1でエラーが発生しました。: ORA-01008: バインドされていない変数があります。 ORA-06512: 行5
どこをどう解釈しているのかわかりませんが、とにかく初期化パラメータCURSOR_SHARINGが'FORCE'または'SIMILAR'の環境下で上記のようなプログラムを実行するとエラーが発生するのです。
ただ、普通はプロシージャを動的に呼び出すなんてことはせず、以下のように記述するでしょうから、このようなエラーに出くわすことはありません。
DBMS_STATS.GATHER_TABLE_STATS('SCOTT','EMP');
しかし、ごく希にどうしてもプロシージャの呼び出しを動的に行いたい時もあるので、CURSOR_SHARINGの機能を使う場合は、あらかじめこういったコーディングをしていないかどうかを確かめておいた方がいいでしょう。
また、プロシージャの呼び出しも動的に行いたいし、CURSOR_SHARINGの機能も使いたいという場合には、CURSOR_SHARINGの機能を使いたい時に一時的に
alter session set cursor_sharing=FORCE;
を実行して、CURSOR_SHARINGの機能を有効化し、終了時に
alter session set cursor_sharing=EXACT;
を実行して元に戻すか、それとは逆に初期化パラメータでCURSOR_SHARINGの機能を有効にし、プロシージャを動的に呼び出す時に一時的に無効にするかのどちらかの方法をとればよさそうです。
というか、Oracleさん...直して^^ゞ
【関連エントリ】
[Oracle] 類似したSQLを強制的に共有する(CURSOR_SHARING) 2005/05/26
[Oracle] CURSOR_SHARING=FORCEの環境でORA-01008エラーが発生 2005/06/06