循环嵌套连接的基本思想如下(以表R(左关系)与表S(右关系)连接为例):
FOR each tuple s in S DO FOR each tuple r in R DO IF r and s join to make a tuple t THEN output t;为了迭代实现此方法,NestLoopState中定义了字段nl_NeedNewOuter和nl_MatchedOuter。当元组处于内层循环时,nl_NeedNewOuter为false,内层循环结束时nl_NeedNewOuter设置为true。为了能够处理Left Outer Join和Anti Join,需要知道内层循环是否找到了满足连接条件的内层元组,此信息由nl_MatchedOuter记录,当内层循环找到符合条件的元组时将其标记为true。
NestLoop执行过程主要是由ExecNestLoop函数来做。该函数主要是一个如上面提到的一个大循环。
该循环执行如下操作:
<1>如果nl_NeedNewOuter为true,则从左子节点获取元组,若获取的元组为NULL则返回空元组并结束执行过程。如果nLNeedNewOuter为false,则继续进行步骤2。
<2>从右子节点获取元组,若为NULL表明内层扫描完成,设置nl_NeedNewOuter为true,跳过步骤3继续循环。
<3>判断右子节点元组是否与当前左子节点元组符合连接条件,若符合则返回连接结果。
以上过程能够完成Inner Join的递归执行过程。但是为了支持其他几种连接则还需要如下两个特殊的处理:
1)当找到符合连接条件的元组后将nl_MatchedOuter标记为true。内层扫描完毕时,通过判断nl_MatchedOuter即可知道是否已经找到满足连接条件的元组,在处理Left Outer Join和Anti Join时需要进行与空元组(nl_NullInnerTupleSlot)的连接,然后将nLMatchedOuter设置为false。
2)当找到满足匹配条件的元组后,对于Semi JOIN和Anti JOIN方法需要设置nl_NeedNewOuter为true。区别在于Anti Join需要不满足连接条件才能返回,所以要跳过返回连接结果继续执行循环。
NestLoop节点的清理过程(ExecEndNestLoop函数)没有特殊处理,只需递归调用左右子节点的清理过程。
2.MergeJoin 节点Mergejoin实现了对排序关系的归并连接算法,归并连接的输人都是已经排好序的。PostgreSQL中Mergejoin算法实现的伪代码如下:
Join { get initial outer and inner tuples INITIALIZE do forever { while (outer != inner) { SKIP_TEST if (outer < inner) advance outer SKIPOUTER_ADVANCE else advance inner SKIPINNER_ADVANCE } mark inner position SKIP_TEST do forever { while (outer == inner) { join tuples JOINTUPLES advance inner position NEXTINNER } advance outer position NEXTOUTER if (outer == mark) TESTOUTER restore inner position to mark TESTOUTER else break // return to top of outer loop } } }算法首先初始化左右子节点,然后执行以下操作(其中对于大小的比较都是指对连接属性值的比较):
1)扫描到第一个匹配的位置,如果左子节点(outer)较大,从右子节点(inner)中获取元组;如果右子节点较大,从左子节点中获取元组。
2)标记右子节点当前的位置。
3)循环执行左子节点==右子节点判断,若符合则连接元组,并获取下一条右子节点元组,否则退出循环执行步骤4。
4)获取下一条左子节点元组。
5)如果左子节点==标记处的右子节点(说明该条左子节点与上一条相等),需要将右子节点扫描位置回退到扫描位置,并返冋步骤3;否则跳转到步骤1。
为了说明归并排序的连接算法,我们以Inner Join为例给出部分执行过程,两个current分别指向输人的当前元组,mark用于标记扫描的位置。
1)首先找到左右序列第一个匹配位置,下图中current(outer)=0小于Current(inner),因此outer的current向后移动。
2)如图所示,当找到匹配项后,则进行连接,使用mark标记当前inner的扫描位置,并将inner的current向后移动。
3)接着判断current(outer) = 1小于current(inner) =2,则将outer的current向后移动,并判断outer是否与mark相同(这是为了发现outer的current与前一个相同的情况)。
4)下图显示current(outer) =2不等于mark(inner) = 1,则继续扫描过程。