您正在查看: 标签 调用者 下的文章

PostgreSQL内部概览执行器

44.6. 执行器

执行器(Theexecutor) 接受规划器/优化器传过来的查询规划然后递归地处理它, 抽取所需要的行集合。它实际上是一个需求-拉动地流水线机制。 每次调用一个规划节点地时候,它都必须给出更多的一个行,或者汇报它已经完成行的传递了。

为了提供一个具体的例子,假设顶端节点是一个 MergeJoin 节点。 在做任何融合之前,首先得抓取两行(每个子规划一行)。 因此执行器递归地调用自己来处理子规划(它从附着在 lefttree 上的子规划开始)。 新的顶端节点(左子规划的顶端节点)假设是,一个 Sort 节点,然后还是需要递归地获取一个输入行。 Sort 节点的子节点可能是一个 SeqScan 节点,代表对一个表的实际读取动作。 这个节点的执行导致执行器从表中抓取一行然后把它返回给调用的节点。 Sort 将不断调用它的子节点以获取需要排序的所有行。 在用尽输入之后(由子节点返回一个 NULL 而不是一行表示),Sort 代码执行排序, 然后就可以返回它的第一个输出行,也就是按照排序顺序输出的第一行。 它仍然保持剩下的行的排序状态,这样在随后有需求的时候,它就可以按照排序顺序返回这些行。

MergeJoin节点也会类似地要求从它的右边子规划获取第一行。 然后它比较这两行看看它们是否能连接; 如果能,那么它给它的调用者返回一个连接行。 在下一次调用的时候,或者是在它无法连接当前的两行的时候就是这次调用的时候, 它抓取其中一个表的下一行(抓取哪个表取决于比较结果如何), 然后再检查看看两个表是否匹配。最后,其中一个子规划耗尽资源, 而MergeJoin返回 NULL ,表明无法继续生成更多的连接行。

复杂的查询可能包含许多层的规划节点,但是一般的过程都是一样的: 每个节点在每次被调用的时候都计算并返回它的下一个输出行。 每个节点同样负责附加上任何规划器赋予它的选择或者投影表达式。

执行器机制是用于计算所有的四种基本 SQL 查询类型的: SELECT,INSERT,UPDATE,DELETE。 对于SELECT而言,顶层的执行器代码只是需要发送查询规划树返回的每一行给客户端。 对于INSERT,返回的每一行都插入到 INSERT 声明的目标表中。 This is done in a special top-level plan node calledModifyTable. 一个简单的INSERT ... VALUES命令创建一个简单的规划树,包含一个 Result 节点, 它只计算得出一个结果行。 但是INSERT ... SELECT可能需要执行器的全部能力。 对于UPDATE,规划器安排每个计算出来的行都包括所有更新的字段, 加上原来的目标行的 TID (行 ID); 执行器的顶层使用这些信息创建一个新的更新过的行,并且标记旧行被删除。 对于 ForDELETE,规划实际上返回的唯一的一个字段是 TID , 然后执行器的顶层简单地使用这个 TID 访问每个目标行,并且把它们标记为已删除。

libpq-C库捷径接口

31.6. 捷径接口

PostgreSQL提供一个发往服务器的函数调用的捷径接口。

Tip: 提示: 这个接口在某种程度上已经废弃了,因为我们可以通过设置一盖准备好的 语句来定义函数调用,从而达到类似的性能和更强大的功能。然后,用二进制参 数和结果传输执行该语句,替换一次捷径函数调用。

函数PQfn请求允许通过捷径接口执行服务器函数。

PGresult *PQfn(PGconn *conn, int fnid, int *result_buf, int *result_len, int result_is_int, const PQArgBlock *args, int nargs);

typedef struct
{int len;int isint;union{ int ptr; int integer;} u;
} PQArgBlock;

fnid参数是待执行的函数的对象标识(OID)。args和nargs定义了要传递给函数的参数;
它们必须匹配已经声明了的函数参数列表。如果某个参数结构的isint字段是真
,那么u.integer值以指定长度(必须是1,2,或者 4 字节) 的整数发送给服务器;
这时候会进行恰当的字节序交换(byte-swapping)。如果isint为假,
那么在
u.ptr里面的指定字节数的数据将不做任何处理发送出去; 这些数据必须是服务器
预期的该函数参数类型的二进制传输格式。result_buf是放置返回值的缓冲区。
调用者必须为返回值分配足够的空间(这里没有检查!)。实际的返回值长度将被放在result_len指向的整数里返回。
如果预期返回值是 1,2 或 4 字节整数,把result_is_int设为 1; 否则设为 0。
把result_is_int设为 1 告诉libpq必要时交换数值字节序,这样就可以正确地传
输成客户机上的整数值。当result_is_int是 0 时,
服务器发送回来的字节串不做修改直接返回。

PQfn总是返回一个有效的PGresult指针。在使用结果之前应该检查结果状态。
当结果不再使用后,调用者有义务使用PQclear释放PGresult。

请注意我们没办法处理空值的参数,空的结果,也没办法在使用这个接口的时候设置有值的结果。