🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 52.4\. 外数据封装查询规划 FDW回调函数`GetForeignRelSize`, `GetForeignPaths`, `GetForeignPlan`和 `PlanForeignModify`必须适合PostgreSQL规划器的工作。 这有一些他们必须做的说明。 在`root`和`baserel`中的信息可以用于减少从外表中(因此降低成本)读取的信息量。 `baserel->baserestrictinfo`特别有趣,正如它包含应该用于过滤读取的行的限制资格测试(`WHERE` clauses)。 (FDW本身不需要执行这些测试,正如核心执行者反而可以检查它们。) `baserel->reltargetlist`可以用于决定需要抓取哪个列;但是注意它仅仅列出通过 `ForeignScan`规划节点发出的列,不是在质量评估中使用的列也不是查询输出列。 各种私有字段可用于FDW规划函数保持信息。一般来说,无论在FDW私有字段存储什么 应该是palloc,所以它将在规划结束后被回收。 `baserel->fdw_private`是`空`指针,可用于FDW规划函数存储与特定外表相关的 信息。当创建`baserel`结点时,核心规划器并不接触它除了初始化为NULL外。 从`GetForeignRelSize`到`GetForeignPaths`和/或者 `GetForeignPaths`到`GetForeignPlan`传递信息是非常有用的, 从而避免重复计算。 `GetForeignPaths`可以通过在`ForeignPath`节点的 `fdw_private`字段存储私有信息标识不同访问路径的含义。 作为`List`指针声明`fdw_private`,但是实际上可以包含任何由于 核心规划器没有接触的东西。然而,最好办法是通过`nodeToString`可倾式表示形式, 用于调试后端可用支持。 `GetForeignPlan`可以检查所选的`ForeignPath`节点的 `fdw_private`字段,并且可以产生放在`ForeignScan` 规划节点中的`fdw_exprs`和`fdw_private`列表, 在执行时间他们可用。这些列表必须在`copyObject`知道如何拷贝的形式中被表示。 `fdw_private`列表没有其他限制,并且不能通过任何方式的核心后端进行解释。 `fdw_exprs`列表如果不是零,那么希望包含在运行时执行的表达式树。 这些树将通过规划器使得它们完全可执行进行后处理。 在`GetForeignPlan`中,往往目标列表可以拷贝到规划节点中。 已通过的scan_clauses列表包含和`baserel->baserestrictinfo`相同分句, 但是为了更好的执行效率可能重新排序。 在简单情况下FDW可以从scan_clauses列表(使用`extract_actual_clauses`)中删除`RestrictInfo`节点, 并且将所有分句放入规划节点的资格列表中,这意味着在运行期间通过执行器将检查所有分句。 更多复杂的FDW可能检查一些内部分句,在这种情况下那些分句可以从规划节点的列表中删除,以便执行器 不会浪费复查它们的时间。 作为一个例子,FDW可能标识一些来自`_foreign_variable_` `=` `_sub_expression_`的限制分句,它决定了在给定`_sub_expression_`的本地评估值的 远程服务器上被执行。在`GetForeignPaths`期间产生了该分句的实际标识, 因为它会影响路径的成本估算。路径的`fdw_private`字段可能包含一个指向 已标识分句的`RestrictInfo`节点的指针。然后`GetForeignPlan`从scan_clauses中 删除该分句,但是增加`_sub_expression_`到`fdw_exprs`以确保 它获得可执行形式。它也可能将控制信息放到规划节点的`fdw_private` 字段以告知执行函数在运行时间执行什么。传送到远程服务器的查询可能涉及到像`WHERE` `_foreign_variable_` = $1的一些内容,使用从`fdw_exprs`表达式树评估中获得的参数值。 FDW应该总是构建至少一个仅仅依赖于表的限制分句的路径,在连接查询中,它也可能选择构建依赖于连接分句的路径, 比如 `_foreign_variable_` `=` `_local_variable_`。该分句没有在`baserel->baserestrictinfo`中找到, 但是必须在关系的连接列表中寻找。 使用分句的路径被称为"参数化路径"。 它必须标识用于使用`param_info`合适值的已选择连接分句的其他关系; 使用`get_baserel_parampathinfo`计算该值。在`GetForeignPlan`中, 连接分句的`_local_variable_`部分将被添加到`fdw_exprs`中, 然后运行时该情况与普通限制分句一样运行。 当规划一个`UPDATE`或者`DELETE`的时候, `PlanForeignModify`可以查找外表的`RelOptInfo`结构, 并且充分使用通过扫描规划函数预先创建的`baserel->fdw_private`数据。 然而,在`INSERT`中不扫描目标表,所以没有`RelOptInfo`。 通过`PlanForeignModify`返回的`List`与`ForeignScan`规划节点 的`fdw_private`列表有相同的限制, 即它必须包含`copyObject`知道如何拷贝的结构。 `UPDATE`或者`DELETE`反对外部数据源支持并发更新,推荐 `ForeignScan`操作锁定抓取的行,也许通过`SELECT FOR UPDATE`的等价物。 当在`SELECT FOR UPDATE/SHARE`引用外表时,FDW可能也会在抓取时选择锁定行。 如果没有做,就有关外表来说, 那么`FOR UPDATE`或者`FOR SHARE`选项本质上是无操作的。 这种操作可能会产生本地表操作上轻微的语义差异,行锁定通常尽可能的延迟: 远程行可能获得锁定即使他们随后没有本地应用限制或者连接条件。 然而,匹配局部语义确实需要每行的额外远程访问,并且不可能依赖于 外部数据源提供的锁定语义内容。