PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 53. 写一个外部数据封装器 | 下一页

# 53.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`选项本质上是无操作的。 这种操作可能会产生本地表操作上轻微的语义差异，行锁定通常尽可能的延迟： 远程行可能获得锁定即使他们随后没有本地应用限制或者连接条件。 然而，匹配局部语义确实需要每行的额外远程访问，并且不可能依赖于 外部数据源提供的锁定语义内容。

上一页 | 起始页 | 下一页
外数据封装辅助函数 | 上一级 | 基因查询优化器