バインドピーク機能とは
バインドピーク機能とはバインド変数を含むSQL文の実行計画をCBOが立てる際、実際にバインド変数にセットされた値を考慮し実行計画を立てることができるようになる機能です。 バインドピーク機能は9iから追加された新機能で隠しパラメータ_optim_peek_user_bindsにより有効(true)と無効(false)を設定することができます。デフォルトはtrueです。
バインドピーク機能の設定方法
本パラメータは隠しパラメータであるためalter文で変更する場合はパラメータをダブルクオーテーションで囲む必要があります。 spfileを使用しておらずpfileを利用している場合はダブルクオーテーションは不要です。セッション単位の場合
alter session set "_optim_peek_user_binds"=true;
システム単位の場合
alter system set "_optim_peek_user_binds"=true scope=both;
バインドピーク機能のメリット
バインドピーク機能を使うことのメリットは実際にバインド変数にセットされた値をもとにカーディナリティ計算がされるため適切な実行計画が選択されやすくなる点です。 具体的には以下のような条件がバインド化されているSQLは適切な実行計画が選択されやすくなる可能性があります。(あくまで一例でありこれに限りません)
- 範囲指定の条件がある(between,<、>)
- 値によってカーディナリティが大きく偏る列が条件指定されており、かつその列のヒストグラムが取得されている
- 列の統計情報上の最小値、最大値から大きくはずれた値が指定されている
また、経験上バインド変数、リテラルどちらで記述されていても実行計画は同じになるケースが多くなります。 バインドピークが無効になっている場合、リテラルかバインド化されているかでORACLEの仕様上の動作として異なる実行計画になる場合があります。
バインドピーク機能のデメリット
最も大きなデメリットはバインド変数にセットされる値が不定(エンドユーザが入力するなど)の場合実行計画が安定しなくなる点です。 バインドピークを有効化するとハードパース時にその時にバインド変数にセットされていた値をもとに実行計画が立てられますが、 これは統計情報に変化がなくともハードパース時にセットされていたバインド変数値によって実行計画が変わってしまう可能性があることを意味します。 結果として、10gまでのバージョンにおいては毎日DBの再起動や共有プールフラッシュを行っているシステムだと日によって(初回実行された時のバインド変数値によって)実行計画が変わり性能が安定しなくなるといった事象が発生することがありました。
11g以降、このデメリットを解消しうる機能として11gR1で優れたカーソル共有、11gR2でカーディナリティフィードバック、12cR1で適応計画といった新機能が追加されていますが、いずれの機能もこのデメリットを完全に払拭できる機能ではありません。 具体的には、優れたカーソル共有はハードパースに近い処理が多発しバインド化のメリットが失われる、カーディナリティフィードバックは動作タイミングが2回目以降である、適応計画は修正される実行計画に制限があるなどです。 また、いずれの機能も発生条件等の詳しい仕様が公開されていないことも懸念点としてあげられます。
バインドピーク機能を使うべきか(当サイト見解)
設計段階でどちらかに決めるとした場合、当サイトでは無効にすべきと考えます。システムの安定稼働を目指すのであれば実行計画の安定はほぼ必須となりバインドピーク機能はこの妨げになるためです。 また、バインドピークを無効化したことで不適切な実行計画が選択されるケースは多くは本番相当のデータでテストをしていれば検知できヒント句などで対応できるものが多いのに対して、 バインドピーク機能が有効であった影響で発生する実行計画のデグレードはテストによる検出することが難しいケースもあり、 さらに上述の新機能等の影響もありORACLEに精通した技術者でなければトラブルシューティングが困難になる可能性がある点も根拠の一つとなります。