2章:where句
7.パラメータ化クエリ
1. バインドパラメータと実行計画の本質的なジレンマ
一見すると矛盾する2つの主張
■ バインドパラメータを使わない
- 値がSQLに直接書かれる
- オプティマイザは値ごとに行数を正確に見積もれる
➡ 常に最適な実行計画を選べる
■ バインドパラメータを使う
- SQL文が完全に同一になる
- 実行計画をキャッシュできる
➡ 解析・最適化コストを削減でき、全体性能は向上
これは矛盾ではなく、どこにコストを払うかのトレードオフ。
2. バインドパラメータを使わない場合の問題
値が変わるたびにSQLが別物になるため
- パース
- 最適化
- 実行計画生成
が毎回発生する
➡「毎回プログラムを再コンパイルして実行する」のと同じ状態
3. バインドパラメータ使用時の制約
オプティマイザの前提
- バインド値の分布を事前に把握できない
- 値は一様に分布していると仮定
- 行数見積もり・コストは常に同じ
➡ 常に同じ実行計画が使われる
4. 値によって実行計画が変わる典型例
1. 偏った分布を持つ列
例:ステータス列
- DONE:件数が非常に多い
- PLANNED:件数が少ない
WHERE status = 'PLANNED'; -- インデックスが有効
WHERE status = 'DONE'; -- フルスキャンが有利
➡ バインドするとどちらも同じ実行計画になり、どちらかが非効率になる
2. パーティショニング
- 値によってスキャン対象パーティションが変わる
- バインドパラメータでは、その判断が事前にできない場合がある
5. 開発者としての結論(重要)
基本方針
- 原則:バインドパラメータを使う
- セキュリティ(SQLインジェクション防止)
- 実行計画キャッシュによる全体性能向上
例外
- 値が実行計画に明確な影響を与える場合のみ注意
例) 極端に偏ったデータ分布, パーティションキー, インデックス使用可否が値で変わる列
➡ それ以外は、最適化を過剰に考えず バインドを使う
6. 複合インデックス設計との関係
バインド前提では
- 「どの値が来ても破綻しない実行計画」
- 「幅広い条件で使える列順」
が重要
➡ 複合インデックスは最悪ケースでも耐えられる設計」にする
まとめ
バインドパラメータは、個々のSQLの最適性よりも
システム全体の安定した高性能を優先するための仕組み であり、
実行計画に明確な影響を与える場合を除いて、常に使うべきである。