执行器接手规划器/优化器创建的计划,并递归地处理之以抽取所需的行集。这本质上是一种需求拉动的管道机制。每次一个计划节点被调用时,它必须交付一个或多个行,或者报告已经完成了行的交付。
为了提供一个具体例子,假设顶层节点是一个MergeJoin
节点。在归并完成之前,两个行必须先被获取(每一个来自于一个子计划)。因此执行器递归地调用它自己去处理子计划(从附加在lefttree
的子计划开始)。新的顶层节点(左子计划的顶层节点),我们说是一个Sort
节点,并且又要递归来获取一个输入行。Sort
的子节点可以是一个SeqScan
节点,表示真正地读取一个表。该节点的执行将会使执行器从表中获取一行并将它返回给调用节点。Sort
节点将反复调用它的子节点来获得所有需要排序的行。当输入耗尽后(子节点将返回一个NULL来标识),Sort
节点执行排序,并且最后能够返回它的第一个输出行,及排序后的第一个。它会把剩下的行保存下来,这样它可以根据后续的要求按照排好的顺序返回这些行。
MergeJoin
节点也会相似地从其右子计划要求第一个行。然后它会比较两个子节点提供的行看它们是否能被连接,如果可以它会返回一个连接行给调用者。在下一次调用时,或者它无法连接当前的输入对时,它会前进到一个表或另一个表的下一行(取决于比较的结果),并再次检查匹配。最后,某个子计划耗尽,MergeJoin
节点返回NULL表示它没有更多连接行可以提供。
复杂的查询可能涉及多层计划节点,但是一般的方法是相同的:每个节点在被调用时计算并返回它的下一个输出行。每个节点同时也负责应用由规划器分配给它的选择或投影表达式。
执行器机制用于评估所有五种基本的SQL查询类型:SELECT
、INSERT
、
UPDATE
、DELETE
和MERGE
。
对于SELECT
,顶层执行器代码只需要将查询计划树返回的每一行发送给客户端。
INSERT ... SELECT
、UPDATE
、DELETE
和
MERGE
实际上是在一个名为ModifyTable
的特殊顶层计划节点下的
SELECT
。
INSERT ... SELECT
将行提供给 ModifyTable
进行插入。
对于 UPDATE
,规划器安排每个计算出的行包含所有更新列的值, 加上原始目标行的 TID (元组ID或行ID);这些数据被提供给 ModifyTable
节点,该节点使用这些信息创建一个新的更新行并标记旧行已删除。
对于 DELETE
,计划实际返回的唯一列是TID, ModifyTable
节点只需使用TID访问每个目标行并将其标记为已删除。
对于 MERGE
, 规划器连接源和目标关系,并包含所有 WHEN
子句所需的列值,加上目标行的TID;
这些数据被提供给 ModifyTable
节点,该节点使用这些信息来决定执行哪个 WHEN
子句,然后根据需要插入、更新或删除目标行。
一个简单的INSERT ... VALUES
命令创建了一个简单的计划树,由一个单独的Result
节点组成,
该节点仅计算一个结果行,将其传递给ModifyTable
执行插入操作。