执行器

执行器接收由规划器/优化器传递过来的规划,然后开始处理顶端节点。在我们给出的例子里面(在例子 \ref{simple_select} 里给出的查询),顶端节点是一个 MergeJoin 节点。

在进行任何融合之前,首先要抓取两条记录(从每个子规划里抓一条)。所以执行器递归地调用它自己以处理子规划(它从附加在 lefttree 上的子规划开始)。新的顶端节点(左边子规划的顶端节点)是一个 SeqScan 节点,同样必须先抓取一条记录然后才能处理节点本身。执行器再次递归地调用自身,处理附加在 lefttreeSeqScan 节点上的子规划。

现在新的顶端节点是一个 Sort 节点。因此,要对整个关系进行排序。当第一次访问 Sort 节点时,执行器开始从 Sort 节点的子查询里抓取记录并把它们在一个临时关系里面(在内存或文件中)排序。(对 Sort 节点的进一步检查将总是从排好序的临时关系里返回一条记录。)

每当处理 Sort 节点需要新的记录时,都会为作为子规划附加上来的 SeqScan 节点递归地调用执行器。然后对该关系(在内部通过数据域 scanrelid 给出的值引用)进行扫描,检索下一条记录。如果记录满足附加在 qpqual 上的条件树则将其返回,否则抓取下一条记录知道条件被满足。如果处理到了关系的最后一条记录,则返回一个 NULL 指针。

MergeJoinlefttree 返回一条记录后,用同样方法处理 righttree。如果两条记录都存在了,执行器就处理 MergeJoin 节点。每当有一个子规划需要一条新的记录时,都进行一次执行器的递归调用以获取记录。如果可以创建一条联合的记录,那么就把这条记录返回并且完成一次完整的规划树的处理。

现在,上面描述的步骤对每条记录执行一次,直到对 MergeJoin 节点的处理返回一个 NULL 指针,表示我们已经处理完毕时为止。