为了理解规则系统的运作方式,有必要了解何时调用它以及它的输入和结果是什么。
规则系统位于解析器和规划器之间。它接收解析器的输出,一个查询树,以及用户定义的重写规则,这些规则也是带有额外信息的查询树,并生成零个或多个查询树作为结果。因此,它的输入和输出始终是解析器本身可以生成的,因此,它所看到的所有内容基本上都可以表示为SQL语句。
那么什么是查询树?它是对SQL语句的内部表示,其中它所构建的各个部分分别存储。如果您设置了配置参数 debug_print_parse
、debug_print_rewritten
或 debug_print_plan
,则可以在服务器日志中显示这些查询树。规则操作也以查询树的形式存储在系统目录 pg_rewrite
中。它们的格式不像日志输出,但它们包含完全相同的信息。
阅读原始查询树需要一些经验。但是,由于SQL查询树的表示足以理解规则系统,本章将不会介绍如何阅读它们。
在阅读本章中的SQL查询树的表示时,有必要能够识别语句在查询树结构中分解成的部分。查询树的部分是
这是一个简单值,指示哪个命令 (SELECT
、INSERT
、UPDATE
、DELETE
) 生成了查询树。
范围表是查询中使用的关系列表。在 SELECT
语句中,这些是在 FROM
关键字之后给出的关系。
每个范围表条目都标识一个表或视图,并告知在查询的其他部分中使用哪个名称调用它。在查询树中,范围表条目通过数字而不是名称来引用,因此,这里并不重要,因为是否出现重复名称就像在SQL语句中一样。这可能发生在规则的范围表合并之后。本章中的示例将不会出现这种情况。
这是一个范围表索引,用于标识查询结果所在的范围表。
SELECT
查询没有结果关系。(SELECT INTO
的特殊情况与 CREATE TABLE
后跟 INSERT ... SELECT
几乎相同,这里不会单独讨论。)
对于 INSERT
、UPDATE
和 DELETE
命令,结果关系是将要执行更改的表(或视图!)。
目标列表是定义查询结果的表达式列表。在 SELECT
的情况下,这些表达式是构建查询最终输出的表达式。它们对应于关键字 SELECT
和 FROM
之间的表达式。(*
只是对关系的所有列名的缩写。它由解析器扩展为各个列,因此规则系统永远不会看到它。)
DELETE
命令不需要正常的目标列表,因为它们不会产生任何结果。相反,规划器会向空目标列表添加一个特殊的CTID条目,以允许执行器找到要删除的行。(CTID在结果关系是普通表时添加。如果是视图,则规则系统将添加一个整行变量,如 第 39.2.4 节 中所述。)
对于 INSERT
命令,目标列表描述了应该进入结果关系的新行。它包括 VALUES
子句中的表达式或 INSERT ... SELECT
中 SELECT
子句中的表达式。重写过程的第一步会为原始命令未分配但具有默认值的任何列添加目标列表条目。任何剩余的列(既没有给定值也没有默认值)将由规划器填充一个常量空表达式。
对于 UPDATE
命令,目标列表描述了应该替换旧行的新的行。在规则系统中,它只包含来自命令的 SET column = expression
部分的表达式。规划器将通过插入表达式来处理缺少的列,这些表达式将从旧行复制值到新行。就像 DELETE
一样,CTID或整行变量被添加,以便执行器可以识别要更新的旧行。
目标列表中的每个条目都包含一个表达式,该表达式可以是常量值、指向范围表中某个关系列的变量、参数或由函数调用、常量、变量、运算符等组成的表达式树。
查询的限定条件是一个表达式,与目标列表条目中包含的表达式非常相似。此表达式的结果值是一个布尔值,它指示最终结果行上的操作 (INSERT
、UPDATE
、DELETE
或 SELECT
) 是否应该执行。它对应于SQL语句。
查询的连接树显示 FROM
子句的结构。对于像 SELECT ... FROM a, b, c
这样的简单查询,连接树只是一个 FROM
项的列表,因为我们允许以任何顺序连接它们。但是,当使用 JOIN
表达式(特别是外部连接)时,我们必须按照连接所示的顺序进行连接。在这种情况下,连接树将显示 JOIN
表达式的结构。与特定 JOIN
子句(来自 ON
或 USING
表达式)相关的限制存储为附加到这些连接树节点的限定条件表达式。事实证明,将顶层 WHERE
表达式存储为附加到顶层连接树项的限定条件也很方便。因此,连接树实际上代表了 SELECT
的 FROM
和 WHERE
子句。
查询树的其他部分,如 ORDER BY
子句,在这里不重要。规则系统在应用规则时会替换一些条目,但这与规则系统的基本原理无关。
如果您在文档中发现任何不正确的地方,与您对特定功能的体验不符,或者需要进一步说明,请使用 此表格 报告文档问题。