gooderp18绿色标准版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
17KB

  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>56.4. Foreign Data Wrapper Query Planning</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /><link rel="prev" href="fdw-helpers.html" title="56.3. Foreign Data Wrapper Helper Functions" /><link rel="next" href="fdw-row-locking.html" title="56.5. Row Locking in Foreign Data Wrappers" /></head><body><div xmlns="http://www.w3.org/TR/xhtml1/transitional" class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">56.4. Foreign Data Wrapper Query Planning</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="fdw-helpers.html" title="56.3. Foreign Data Wrapper Helper Functions">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="fdwhandler.html" title="Chapter 56. Writing a Foreign Data Wrapper">Up</a></td><th width="60%" align="center">Chapter 56. Writing a Foreign Data Wrapper</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 12.4 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="fdw-row-locking.html" title="56.5. Row Locking in Foreign Data Wrappers">Next</a></td></tr></table><hr></hr></div><div class="sect1" id="FDW-PLANNING"><div class="titlepage"><div><div><h2 class="title" style="clear: both">56.4. Foreign Data Wrapper Query Planning</h2></div></div></div><p>
  3. The FDW callback functions <code class="function">GetForeignRelSize</code>,
  4. <code class="function">GetForeignPaths</code>, <code class="function">GetForeignPlan</code>,
  5. <code class="function">PlanForeignModify</code>, <code class="function">GetForeignJoinPaths</code>,
  6. <code class="function">GetForeignUpperPaths</code>, and <code class="function">PlanDirectModify</code>
  7. must fit into the workings of the <span class="productname">PostgreSQL</span> planner.
  8. Here are some notes about what they must do.
  9. </p><p>
  10. The information in <code class="literal">root</code> and <code class="literal">baserel</code> can be used
  11. to reduce the amount of information that has to be fetched from the
  12. foreign table (and therefore reduce the cost).
  13. <code class="literal">baserel-&gt;baserestrictinfo</code> is particularly interesting, as
  14. it contains restriction quals (<code class="literal">WHERE</code> clauses) that should be
  15. used to filter the rows to be fetched. (The FDW itself is not required
  16. to enforce these quals, as the core executor can check them instead.)
  17. <code class="literal">baserel-&gt;reltarget-&gt;exprs</code> can be used to determine which
  18. columns need to be fetched; but note that it only lists columns that
  19. have to be emitted by the <code class="structname">ForeignScan</code> plan node, not
  20. columns that are used in qual evaluation but not output by the query.
  21. </p><p>
  22. Various private fields are available for the FDW planning functions to
  23. keep information in. Generally, whatever you store in FDW private fields
  24. should be palloc'd, so that it will be reclaimed at the end of planning.
  25. </p><p>
  26. <code class="literal">baserel-&gt;fdw_private</code> is a <code class="type">void</code> pointer that is
  27. available for FDW planning functions to store information relevant to
  28. the particular foreign table. The core planner does not touch it except
  29. to initialize it to NULL when the <code class="literal">RelOptInfo</code> node is created.
  30. It is useful for passing information forward from
  31. <code class="function">GetForeignRelSize</code> to <code class="function">GetForeignPaths</code> and/or
  32. <code class="function">GetForeignPaths</code> to <code class="function">GetForeignPlan</code>, thereby
  33. avoiding recalculation.
  34. </p><p>
  35. <code class="function">GetForeignPaths</code> can identify the meaning of different
  36. access paths by storing private information in the
  37. <code class="structfield">fdw_private</code> field of <code class="structname">ForeignPath</code> nodes.
  38. <code class="structfield">fdw_private</code> is declared as a <code class="type">List</code> pointer, but
  39. could actually contain anything since the core planner does not touch
  40. it. However, best practice is to use a representation that's dumpable
  41. by <code class="function">nodeToString</code>, for use with debugging support available
  42. in the backend.
  43. </p><p>
  44. <code class="function">GetForeignPlan</code> can examine the <code class="structfield">fdw_private</code>
  45. field of the selected <code class="structname">ForeignPath</code> node, and can generate
  46. <code class="structfield">fdw_exprs</code> and <code class="structfield">fdw_private</code> lists to be
  47. placed in the <code class="structname">ForeignScan</code> plan node, where they will be
  48. available at execution time. Both of these lists must be
  49. represented in a form that <code class="function">copyObject</code> knows how to copy.
  50. The <code class="structfield">fdw_private</code> list has no other restrictions and is
  51. not interpreted by the core backend in any way. The
  52. <code class="structfield">fdw_exprs</code> list, if not NIL, is expected to contain
  53. expression trees that are intended to be executed at run time. These
  54. trees will undergo post-processing by the planner to make them fully
  55. executable.
  56. </p><p>
  57. In <code class="function">GetForeignPlan</code>, generally the passed-in target list can
  58. be copied into the plan node as-is. The passed <code class="literal">scan_clauses</code> list
  59. contains the same clauses as <code class="literal">baserel-&gt;baserestrictinfo</code>,
  60. but may be re-ordered for better execution efficiency. In simple cases
  61. the FDW can just strip <code class="structname">RestrictInfo</code> nodes from the
  62. <code class="literal">scan_clauses</code> list (using <code class="function">extract_actual_clauses</code>) and put
  63. all the clauses into the plan node's qual list, which means that all the
  64. clauses will be checked by the executor at run time. More complex FDWs
  65. may be able to check some of the clauses internally, in which case those
  66. clauses can be removed from the plan node's qual list so that the
  67. executor doesn't waste time rechecking them.
  68. </p><p>
  69. As an example, the FDW might identify some restriction clauses of the
  70. form <em class="replaceable"><code>foreign_variable</code></em> <code class="literal">=</code>
  71. <em class="replaceable"><code>sub_expression</code></em>, which it determines can be executed on
  72. the remote server given the locally-evaluated value of the
  73. <em class="replaceable"><code>sub_expression</code></em>. The actual identification of such a
  74. clause should happen during <code class="function">GetForeignPaths</code>, since it would
  75. affect the cost estimate for the path. The path's
  76. <code class="structfield">fdw_private</code> field would probably include a pointer to
  77. the identified clause's <code class="structname">RestrictInfo</code> node. Then
  78. <code class="function">GetForeignPlan</code> would remove that clause from <code class="literal">scan_clauses</code>,
  79. but add the <em class="replaceable"><code>sub_expression</code></em> to <code class="structfield">fdw_exprs</code>
  80. to ensure that it gets massaged into executable form. It would probably
  81. also put control information into the plan node's
  82. <code class="structfield">fdw_private</code> field to tell the execution functions what
  83. to do at run time. The query transmitted to the remote server would
  84. involve something like <code class="literal">WHERE <em class="replaceable"><code>foreign_variable</code></em> =
  85. $1</code>, with the parameter value obtained at run time from
  86. evaluation of the <code class="structfield">fdw_exprs</code> expression tree.
  87. </p><p>
  88. Any clauses removed from the plan node's qual list must instead be added
  89. to <code class="literal">fdw_recheck_quals</code> or rechecked by
  90. <code class="literal">RecheckForeignScan</code> in order to ensure correct behavior
  91. at the <code class="literal">READ COMMITTED</code> isolation level. When a concurrent
  92. update occurs for some other table involved in the query, the executor
  93. may need to verify that all of the original quals are still satisfied for
  94. the tuple, possibly against a different set of parameter values. Using
  95. <code class="literal">fdw_recheck_quals</code> is typically easier than implementing checks
  96. inside <code class="literal">RecheckForeignScan</code>, but this method will be
  97. insufficient when outer joins have been pushed down, since the join tuples
  98. in that case might have some fields go to NULL without rejecting the
  99. tuple entirely.
  100. </p><p>
  101. Another <code class="structname">ForeignScan</code> field that can be filled by FDWs
  102. is <code class="structfield">fdw_scan_tlist</code>, which describes the tuples returned by
  103. the FDW for this plan node. For simple foreign table scans this can be
  104. set to <code class="literal">NIL</code>, implying that the returned tuples have the
  105. row type declared for the foreign table. A non-<code class="symbol">NIL</code> value must be a
  106. target list (list of <code class="structname">TargetEntry</code>s) containing Vars and/or
  107. expressions representing the returned columns. This might be used, for
  108. example, to show that the FDW has omitted some columns that it noticed
  109. won't be needed for the query. Also, if the FDW can compute expressions
  110. used by the query more cheaply than can be done locally, it could add
  111. those expressions to <code class="structfield">fdw_scan_tlist</code>. Note that join
  112. plans (created from paths made by <code class="function">GetForeignJoinPaths</code>) must
  113. always supply <code class="structfield">fdw_scan_tlist</code> to describe the set of
  114. columns they will return.
  115. </p><p>
  116. The FDW should always construct at least one path that depends only on
  117. the table's restriction clauses. In join queries, it might also choose
  118. to construct path(s) that depend on join clauses, for example
  119. <em class="replaceable"><code>foreign_variable</code></em> <code class="literal">=</code>
  120. <em class="replaceable"><code>local_variable</code></em>. Such clauses will not be found in
  121. <code class="literal">baserel-&gt;baserestrictinfo</code> but must be sought in the
  122. relation's join lists. A path using such a clause is called a
  123. <span class="quote">“<span class="quote">parameterized path</span>”</span>. It must identify the other relations
  124. used in the selected join clause(s) with a suitable value of
  125. <code class="literal">param_info</code>; use <code class="function">get_baserel_parampathinfo</code>
  126. to compute that value. In <code class="function">GetForeignPlan</code>, the
  127. <em class="replaceable"><code>local_variable</code></em> portion of the join clause would be added
  128. to <code class="structfield">fdw_exprs</code>, and then at run time the case works the
  129. same as for an ordinary restriction clause.
  130. </p><p>
  131. If an FDW supports remote joins, <code class="function">GetForeignJoinPaths</code> should
  132. produce <code class="structname">ForeignPath</code>s for potential remote joins in much
  133. the same way as <code class="function">GetForeignPaths</code> works for base tables.
  134. Information about the intended join can be passed forward
  135. to <code class="function">GetForeignPlan</code> in the same ways described above.
  136. However, <code class="structfield">baserestrictinfo</code> is not relevant for join
  137. relations; instead, the relevant join clauses for a particular join are
  138. passed to <code class="function">GetForeignJoinPaths</code> as a separate parameter
  139. (<code class="literal">extra-&gt;restrictlist</code>).
  140. </p><p>
  141. An FDW might additionally support direct execution of some plan actions
  142. that are above the level of scans and joins, such as grouping or
  143. aggregation. To offer such options, the FDW should generate paths and
  144. insert them into the appropriate <em class="firstterm">upper relation</em>. For
  145. example, a path representing remote aggregation should be inserted into
  146. the <code class="literal">UPPERREL_GROUP_AGG</code> relation, using <code class="function">add_path</code>.
  147. This path will be compared on a cost basis with local aggregation
  148. performed by reading a simple scan path for the foreign relation (note
  149. that such a path must also be supplied, else there will be an error at
  150. plan time). If the remote-aggregation path wins, which it usually would,
  151. it will be converted into a plan in the usual way, by
  152. calling <code class="function">GetForeignPlan</code>. The recommended place to generate
  153. such paths is in the <code class="function">GetForeignUpperPaths</code>
  154. callback function, which is called for each upper relation (i.e., each
  155. post-scan/join processing step), if all the base relations of the query
  156. come from the same FDW.
  157. </p><p>
  158. <code class="function">PlanForeignModify</code> and the other callbacks described in
  159. <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-UPDATE" title="56.2.4. FDW Routines for Updating Foreign Tables">Section 56.2.4</a> are designed around the assumption
  160. that the foreign relation will be scanned in the usual way and then
  161. individual row updates will be driven by a local <code class="literal">ModifyTable</code>
  162. plan node. This approach is necessary for the general case where an
  163. update requires reading local tables as well as foreign tables.
  164. However, if the operation could be executed entirely by the foreign
  165. server, the FDW could generate a path representing that and insert it
  166. into the <code class="literal">UPPERREL_FINAL</code> upper relation, where it would
  167. compete against the <code class="literal">ModifyTable</code> approach. This approach
  168. could also be used to implement remote <code class="literal">SELECT FOR UPDATE</code>,
  169. rather than using the row locking callbacks described in
  170. <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-ROW-LOCKING" title="56.2.5. FDW Routines for Row Locking">Section 56.2.5</a>. Keep in mind that a path
  171. inserted into <code class="literal">UPPERREL_FINAL</code> is responsible for
  172. implementing <span class="emphasis"><em>all</em></span> behavior of the query.
  173. </p><p>
  174. When planning an <code class="command">UPDATE</code> or <code class="command">DELETE</code>,
  175. <code class="function">PlanForeignModify</code> and <code class="function">PlanDirectModify</code>
  176. can look up the <code class="structname">RelOptInfo</code>
  177. struct for the foreign table and make use of the
  178. <code class="literal">baserel-&gt;fdw_private</code> data previously created by the
  179. scan-planning functions. However, in <code class="command">INSERT</code> the target
  180. table is not scanned so there is no <code class="structname">RelOptInfo</code> for it.
  181. The <code class="structname">List</code> returned by <code class="function">PlanForeignModify</code> has
  182. the same restrictions as the <code class="structfield">fdw_private</code> list of a
  183. <code class="structname">ForeignScan</code> plan node, that is it must contain only
  184. structures that <code class="function">copyObject</code> knows how to copy.
  185. </p><p>
  186. <code class="command">INSERT</code> with an <code class="literal">ON CONFLICT</code> clause does not
  187. support specifying the conflict target, as unique constraints or
  188. exclusion constraints on remote tables are not locally known. This
  189. in turn implies that <code class="literal">ON CONFLICT DO UPDATE</code> is not supported,
  190. since the specification is mandatory there.
  191. </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="fdw-helpers.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="fdwhandler.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="fdw-row-locking.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">56.3. Foreign Data Wrapper Helper Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 56.5. Row Locking in Foreign Data Wrappers</td></tr></table></div></body></html>
上海开阖软件有限公司 沪ICP备12045867号-1