执行器接手规划器/优化器创建的计划,并递归地处理之以抽取所需的行集。这本质上是一种需求拉动的管道机制。每次一个计划节点被调用时,它必须交付一个或多个行,或者报告已经完成了行的交付。
为了提供一个具体例子,假设顶层节点是一个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
feeds the rows up
to ModifyTable
for insertion. For
UPDATE
, the planner arranges that each
computed row includes all the updated column values, plus the
TID (tuple ID, or row ID) of the original
target row; this data is fed up to the ModifyTable
node, which uses the information to create a new updated row and
mark the old row deleted. For DELETE
, the only
column that is actually returned by the plan is the TID, and the
ModifyTable
node simply uses the TID to visit each
target row and mark it deleted. For MERGE
, the
planner joins the source and target relations, and includes all
column values required by any of the WHEN
clauses,
plus the TID of the target row; this data is fed up to the
ModifyTable
node, which uses the information to
work out which WHEN
clause to execute, and then
inserts, updates or deletes the target row, as required.
一个简单的INSERT ... VALUES
命令创建了一个简单的计划树,由一个单独的Result
节点组成,
该节点仅计算一个结果行,将其传递给ModifyTable
执行插入操作。