プランナ/オプティマイザの役割は最適な実行計画を作ることです。 ある与えられたSQL問い合わせは(それがある問い合わせツリーになるのですが)、同じ結果をもたらす、多くの異なった方法で実際には実行できます。 もしもコンピュータの演算として可能であれば、問い合わせオプティマイザは可能な実行計画をすべて検証し、実行するとした場合に一番早く結果をもたらすと想定される実行計画を選択します。
場合によっては、問い合わせがどう実行されるか、可能性のある全ての手段を検証するため、膨大な時間とメモリ空間を消費する可能性があります。 特に数多くの結合操作に問い合わせが関わった時です。 相応な(必ずしも最適ではありませんが)問い合わせ計画を、相応な時間内で決定するためPostgreSQLは結合の数が閾値を越えた場合、遺伝的問い合わせオプティマイザ(58章遺伝的問い合わせ最適化参照)を使用します(geqo_thresholdを参照ください)。
このプランナの検索手順は、実際には経路という名前のデータ構造を使用します。 経路とは、プランナが決定を行うために必要な情報のみに切り詰めた単なる計画の表現です。 最も安価である経路が決定された後、全てが揃った計画ツリーが作成されてエクゼキュータに渡されます。 これはつまり、要求されている実行計画はエクゼキュータがそれを実行するために十分な詳しい内容を所有していることを表しています。 本節の残りでは、経路と計画の違いについて無視します。
プランナ/オプティマイザは、問い合わせの中で使用される個々のリレーション(テーブル)をスキャンするための計画を生成することから始めます。
各リレーション上で利用できるインデックスにより実行可能な計画が決まります。
リレーションをシーケンシャルスキャンする可能性は常にありますので、シーケンシャルスキャンを使用する計画は常に作成されます。
リレーション上にインデックス(例えばB-treeインデックス)が定義され、問い合わせにはrelation.attribute OPR constant
という条件があるとしましょう。
もしrelation.attribute
がB-treeインデックスのキーと一致し、OPR
がインデックスの演算子クラスに列挙されている演算子の1つであれば、リレーションをスキャンするためにB-treeインデックスを使用する別の計画が作られます。
さらに他のインデックスが存在し、問い合わせの中で条件がインデックスのキーに一致した場合、なおその上に計画が検討されます。インデックススキャン計画は、問い合わせの (もし存在すれば)ORDER BY
句に一致するソート順、もしくはマージ結合に便利なソート順を所有するインデックスに対して生成されます(以下を参照してください)。
問い合わせが2つ以上のリレーションの結合を必要とすると、リレーションを結合する計画は、単一のリレーションをスキャンするために全ての実行可能な計画が探し出された後に検討されます。3つの実行可能な結合戦略を示します。
ネステッドループ結合: 左側のリレーションの中で見つけられた行ごとに右側のリレーションが1回スキャンされます。 この戦略は実装が簡単ですが、時間がかかる場合があります (とは言っても右側のリレーションがインデックススキャンによってスキャン可能であればよい戦略になります。 右側のインデックススキャンのキーとして左側のリレーションの現在の行の値を使用することができます。)
マージ結合: 結合を開始する前に、それぞれのリレーションを結合属性でソートします。 そして、2つのリレーションを並行してスキャンし、一致する行を結合行の形にまとめます。 それぞれのリレーションがたった1回しかスキャンされなくて済むのでこの結合は魅力的です。 要求されるソートは、明示的なソート段階、または、結合キー上のインデックスを使用して適切な順序でリレーションをスキャンすることにより行われます。
ハッシュ結合: 右側のリレーションがハッシュキーとして結合属性を用いて初めにスキャンされ、ハッシュテーブルに読み込まれます。 次に左側のリレーションがスキャンされ、見つかったそれぞれの行に相応しい値が、右側のリレーションの行を探し出すためのハッシュキーとして使われます。
問い合わせが3つ以上のリレーションを含む場合、それぞれ2つの入力を持つ結合段階のツリーによって最終結果を構築しなければなりません。 プランナは最も低コストな計画を見つけ出すために、あり得る異なった結合順序を検証します。
問い合わせがgeqo_thresholdより少ないリレーションを使用する場合、最適な結合シーケンスを見つけ出すため、完璧に近い検索が行われます。
プランナはWHERE
条件での対応する結合句が存在する(すなわち、where rel1.attr1=rel2.attr2
のような制約に対して)、あらゆる2つのリレーション間の結合を優先的に考慮します。
結合句のない結合ペアは他に選択のない場合に考慮されます。つまり、ある特定のリレーションが他のどんなリレーションに対しても有効な結合句を持たない場合です。
すべての有効な計画はプランナが考慮したすべての結合ペアに対し生成され、最も安価な(と評価された)ものが選択されます。
geqo_threshold
を上回ると、考慮された結合シーケンスは58章遺伝的問い合わせ最適化に記載されているように経験則で決定されます。
そうでない時、処理は変わりません。
最終的な計画ツリーは基になっているリレーションのシーケンシャルもしくはインデックススキャン、そして必要に応じてネステッドループ、マージ、またはハッシュ結合のノード、さらにはソートまたは集約関数計算ノードのような必要とされる補助の手順から構成されます。
これらほとんどの計画ノード型は選択(特定の論理演算条件に合致しない行を破棄すること)および射影(与えられた列の値に基づき派生した列の集合を計算すること、つまり必要なところでスカラ式の評価をすること)を行う追加的能力を持っています。
プランナの1つの責任は、WHERE
句から選択条件を付加して計画ツリーの最も適切なノードに対し必要とされる出力式を計算することです。