プランナ/オプティマイザの機能は最適な実行プランを作成することです。 始めに、問合せの中に出てくるリレーションに対して、可能性のある全ての スキャンと join を結合します。オプティマイザがやることは同一の結果を 導く全てのパスに対して、それぞれのパスを実行する上での経済効果を推定し、 最も効率の良いパスを見つけ出すことです。
プランナ/オプティマイザは問合せに出現するリレーションに対して定義される インデックスのタイプに基づいてどのプランが生成されるべきか判断します。 リレーションに対して逐次スキャンを行う可能性は常にあるため、 逐次スキャンは必ず生成されます。(たとえば B-tree インデックスのように) リレーションに対してインデックスが定義され、問合せに relation.attribute OPR constant 制限が含まれて いるとします。もし relation.attribute が B-tree インデックスのキーに一致し、OPR が単に '<>' の場合は、 リレーションをスキャンする B-tree インデックスを使用して他のプラン が作成されます。更にいくつかのインデックスが存在し、あるインデックス のキーと問い合わせの中の条件が一致した場合は更なるプランが検討 されます。
単一のリレーションをスキャンする全ての実行可能プランが検出された後、 リレーションを join するプランが作成されます。プランナ/オプティマイザ は、対応する where 制限事項の中の join 句が存在する、 (すなわち where rel1.attr1=rel2.attr2 が存在するような制限) 二つ毎のリレーション間の join のみを検証します。 プランがプランナ/オプティマイザによって検討された全ての可能性のある プランがそれぞれの join の組合せに対して生成されます。 可能性のある join の戦略として三種類あげられます。
ネストした逐次代入 join: 左側のリレーションで 見つかった全てのタプルに対して右側のリレーションが一度だけスキャン されます。この戦略は実装が易しいのですが、処理に時間を要します。
マージ・ソート join: join が開始される前に、 join 属性でひとつひとつのリレーションがソートされます。次に、 二つのリレーションが join 属性で並んでいることに注目し、その 二つがマージされます。この種の join は全てのリレーションを一度だけ スキャンすれば良いため、より魅力的なものになっています。
ハッシュ join: join 属性に基づき、右側の リレーションが最初にハッシュされます。次に、左側のリレーションが スキャンされ検出された全てのタプルの値が右側のリレーションのタプル を特定するハッシュキーとして使用されます。
ここでプランに現れるノードについて簡単に記述します。図 \ref{plan} は 例 \ref{simple_select} の問合せに対して作成されたプランを示しています。
プランの最上ノードは、lefttree に付くものと righttree に付くものの、二つの継承を持った MergeJoin ノードです。それぞれのサブノードは、その join の一つのリレーションを表します。上述したように、マージ・ソート join ではそれぞれのリレーションがソートされていることが必要です。 従って、それぞれのサブプランに Sort ノードが あるわけです。問合せ(s.sno > 2)において与え られた追加の制限事項は可能な限り下位に押し下げられ、対応するサブプラン の SeqScan リーフノードの qpqual フィールドに付けられます。
MergeJoin ノードの mergeclauses に 付けられたリストは join 属性についての情報を含んでいます。mergeclauses リスト(および targetlist も同様)の中に出現する VAR ノードの varno フィールドに対する値、 65000 と 65001 は現在のノードのタプルが検証されるのではなく、次に深い ノード(すなわちサブノードの最上ノード)のタプルが替わりとして検証されることを意味 しています。
図 \ref{plan} に出てくる全ての Sort と SeqScan ノードは targetlist を既に取得していますが、充分なスペースが充分でないため MergeJoin ノードに対する一つだけが描かれています。
プランナ/オプティマイザによってもたらされる他の機能として Expr と Oper ノードの中の 演算子 id を 修正することがあります。前に述べたように、Postgres は 各種異なったデータ型をサポートするとともにユーザが定義する型も使用可能です。 巨大な量の関数と演算子の保守を可能とするためそれらをシステムテーブルに保存しておく 必要があります。それぞれの関数や演算子は一意な演算子 id が与えられます。 条件などの中で使用される属性の型に従って、適切な演算子 id が使用されなければ なりません。