2.6. 执行器

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

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

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

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

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

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