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