要理解规则系统如何工作,必须知道它何时被调用以及它的输入和结果是什么。
规则系统位于解析器和计划器之间。它接收解析器的输出(一个查询树)和用户定义的重写规则(也是带有额外信息的查询树),并创建零个或多个作为结果的查询树。因此,它的输入和输出始终是解析器本身可以生成的东西,因此,它所看到的一切基本上都可以表示为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
子句中的表达式组成。重写过程的第一步是为原始命令未分配但具有默认值的任何列添加目标列表条目。任何剩余的列(既没有给定值也没有默认值)将由计划器使用常量 null 表达式填充。
对于 UPDATE
命令,目标列表描述应替换旧行的新行。在规则系统中,它仅包含命令的 SET column = expression
部分的表达式。计划器将通过插入将旧行的值复制到新行的表达式来处理丢失的列。正如 DELETE
一样,添加一个CTID或整行变量,以便执行器可以标识要更新的旧行。
目标列表中的每个条目都包含一个表达式,该表达式可以是常量值、指向范围表中一个关系的列的变量、参数或由函数调用、常量、变量、运算符等组成的表达式树。
查询的限定是一个表达式,很像目标列表条目中包含的表达式之一。此表达式的结果值是一个布尔值,指示是否应执行最终结果行的操作(INSERT
、UPDATE
、DELETE
或 SELECT
)。它对应于SQL语句。
查询的连接树显示 FROM
子句的结构。对于像 SELECT ... FROM a, b, c
这样的简单查询,连接树只是 FROM
项的列表,因为我们允许以任何顺序连接它们。但是当使用 JOIN
表达式,特别是外部连接时,我们必须按照连接所示的顺序进行连接。在这种情况下,连接树显示 JOIN
表达式的结构。与特定 JOIN
子句关联的限制(来自 ON
或 USING
表达式)作为附加到这些连接树节点的限定表达式存储。事实证明,将顶级 WHERE
表达式存储为附加到顶级连接树项的限定也方便。所以实际上连接树同时表示 FROM
和 WHERE
子句。
查询树的其他部分,如 ORDER BY
子句,在这里不感兴趣。规则系统在应用规则时会替换其中的一些条目,但这与规则系统的基本原理关系不大。
如果您在文档中发现任何不正确、与您特定功能的使用体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。