38.1. 查询树

要理解规则系统如何工作,首先要知道规则何时被激发以及它的输入和结果是什么。

规则系统位于分析器和规划器之间。以分析器输出的查询树以及用户定义的重写规则作为输入, 重写规则也是一个查询树,只不过增加了一些扩展信息,然后创建零个或者多个查询树作为结果。 所以它的输入和输出仍然是那些分析器可以生成的东西,因而任何规则系统看到的东西都是可以用 SQL语句表达的。

那么什么是查询树呢?它是一个SQL语句的内部表现形式, 这时组成该语句的每个独立部分都是分别存储的。如果你设置了配置参数 debug_print_parse, debug_print_rewritten, 或debug_print_plan,那么就可以在服务器日志中看到这些查询树。 规则动作也是以查询树的方式存储的,存放在系统表pg_rewrite里面。 不过不是用像调试输出那样的格式,但包含的内容是完全一样的。

阅读一个裸查询树需要一定的经验,但是因为理解查询树的SQL 表现就足以理解规则系统,所以这份文档将不会告诉你如何读取它们。

当读取本章中查询树的SQL表现时, 必须能够识别该语句被分解后放在查询树里的成员。查询树的成员有

命令类型(command type)

这是一个简单的值,说明哪条命令(SELECT, INSERT, UPDATE, DELETE)生成这个查询树。

范围表(range table)

范围表是一个查询中使用的关系的列表。在SELECT 语句里就是在FROM关键字后面给出的关系。

每个范围表表示一个表或一个视图,表明是查询里哪个成员调用了它。在查询树里, 范围表是用代号而不是用名字引用的,所以这里不用像在SQL 语句里一样关心是否有重名问题。这种情况在引入了规则的范围表后可能会发生。 本章的例子将不讨论这种情况。

结果关系(result relation)

这是一个范围表的索引,用于标识查询结果前往的表。

SELECT查询通常没有结果关系。特例SELECT INTO 几乎等于一个跟随INSERT ... SELECTCREATE TABLE,所以这里就不单独讨论了。

INSERT, UPDATE, DELETE命令里, 结果关系是更改发生影响的表或视图。

目标列(target list)

目标列是一列定义查询结果的表达式。在SELECT的情况下, 这些表达式就是构建查询的最终输出的东西。它们是位于SELECTFROM关键字之间的表达式(* 只是表明一个关系的所有字段的缩写,它被分析器扩展为独立的字段,因此规则系统永远看不到它)。

DELETE不需要正常的目标列是因为它们不产生任何结果。 相反的,规划器会向空目的标列中增加一条特殊的CTID记录, 以允许执行器找到被删除的行。(当结果关系是一个普通的表时添加CTID。 如果结果关系是一个视图,则添加所有的行变量,描述在Section 38.2.4。)

对于INSERT命令里面,目标列描述了应该进入结果关系的新行。 这些行由那些在VALUES子句里的表达式或在INSERT ... SELECT 语句里的SELECT子句里面的表达式构成。 重写过程的第一步就是为任何不是由原始的查询赋值,并且有缺省值的字段增加目标列表项。 任何其它的字段(既无给出值也无缺省值)将由规划器自动赋予一个常量 NULL 表达式。

对于UPDATE命令,目标列描述应该替换旧行的新行。在规则系统里, 它只包含来自命令的SET column = expression部分抽取的表达式。 这时,规划器将通过插入从旧行抽取数据到新行的表达式的方法处理缺失的字段。 就像对DELETE,规则系统添加CTID或整行变量使执行者可以识别要被更新的旧行。

目标列里的每个元素都包含着一个表达式,它可以为常量值、一个指向某个范围表里面的关系的一个字段的变量、 一个参数、一个由函数调用/常量/变量/操作符等构成的表达式树。

条件(qualification)

查询条件是一个表达式,它非常类似那些包含在目标列里的条目。这个表达式的值是一个布尔值, 通过此值来判断对最终结果行是否要执操作(INSERT, UPDATE, DELETE, 或 SELECT)。它是一个SQL 语句的WHERE子句。

连接树(join tree)

查询的连接树显示了FROM子句的结构。对于像SELECT ... FROM a, b, c 这样的简单查询,连接树只是一个FROM项的简单列表,因为允许以任意顺序连接它们。 但如果使用了JOIN表达式(尤其是外连接的时候),就必须按照该连接显示的顺序进行连接。 在这种情况下,连接树显示JOIN表达式的结构。与特定的JOIN子句(来自ONUSING表达式)相关的限制做为附加在那些连接树节点的条件表达式存储。 事实证明把顶层WHERE表达式也当做附加在顶层连接树项的条件来存储是非常方便的。 所以实际上连接树代表SELECT语句的FROMWHERE子句。

其它(others)

查询树的其它部分,像ORDER BY子句,不准备在这里讨论。 规则系统在附加规则时将在那里(ORDER BY 子句)替换一些条目,但是这对于规则系统的基本原理并没有多大关系。