在找完扫描一个关系的所有可能的规划后,接着创建联接各个关系的规划。规划器/优化器认为只有在每两个关系之间存在联接,对应地在 where 条件里存在一条 join 子句(也就是说,存在象 where rel1.attr1=rel2.attr2 这样的约束)。规划器/优化器为它们认为可能的所有的联接关系对生成一个规划。有三种可能的联接策略:
融合排序联接(merge sort join):在联接开始之前,每个关系都对联接字段进行排序。然后两个关系融合到一起,认为两个关系都对联接字段进行了排序。这种联合更有吸引力,因为每个关系都只用扫描一次。
哈希联接(hash join):右边的关系首先对它的联接字段进行哈希运算。然后扫描左边的关系,并将找到的每条记录的合适的值作为哈希键字用以定位右边关系里的记录。
规划的顶端节点是一个 MergeJoin 节点,它有两个下级节点,一个附加在域 lefttree 上,而另一个附加在域 righttree 上。每个子节点代表一个联接的关系。如上面所述,一个融合联接要求每个关系先被排序。这就是为什么我们在每个子规划里有一个 Sort 节点的原因。查询里附加的条件(s.sno > 2)被尽可能地向下推,并且附加在对应的子规划的叶节点 SeqScan 的 qpqual 域上。
附加在节点 MergeJoin 的域 mergeclauses 的列表包含关于联接属性的信息。 mergeclauses 列表里(还有 targetlist 里)出现的 VAR 节点的数据域 varno 的值 65000 和 65001 意味着不考虑当前节点的记录,而是使用下一"更深"节点(也就是说,子规划的顶端节点)的记录。
请注意图 \ref{plan} 里的每个 Sort 和 SeqScan 节点都有一个 targetlist,但因为空间不够,只有 MergeJoin 节点的画出来了。
规划器/优化器执行的另一个任务是填补 Expr 和 Oper 节点里的操作符id。如上所述,Postgres 支持广范围的不同的数据类型,甚至可以使用用户定义类型。为了能够维护这些数目巨大的函数和操作符,有必要把它们存放在系统表里。每个函数和操作符有一个唯一的操作符 id。根据在资格条件等地方使用的字段的类型,必须选用合适的操作符 id。