13.2. Query Tree(查询树)是什么?

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

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

那么什么是 query tree(查询树)呢? 它是一个 SQL 语句的内部表现形式,这时组成该语句的每个部分都是分别存储的. 当你用调试级别(debuglevel)4 运行 PostgreSQL 后端并且在 SQL 界面交互地输入查询命令时可以看到这些查询树. 在 pg_rewrite 系统表里的规则动作也是以查询树的方式存储的. 不过不是用象调试输出那样的格式,但包含的内容是完全一样的.

读查询树的内容需要一定的经验, 我开始在规则系统上干活时曾经历了一段很困难的时光. 我还记得当初我站在一台咖啡机面前把杯子当做目标列, 水和咖啡粉当作可排列的元素,所有按钮是资格表达式来想象查询树的情景. 因为理解查询树的 SQL 表现就足以理解规则系统, 所以这份文档将不会告诉你如何读取它们. 这篇文档可能帮助你学习规则系统和它的命名习惯以便于后面的描述.

13.2.1. Query Tree(查询树)的成员

当我们读取这份文档中查询树的SQL 表现时, 我们必须能够识别该语句被分解后放在查询树里的成员. 查询树的成员有

命令类型 ( command type )

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

范围表 (range table)

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

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

结果关系(result relation)

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

SELECT 查询通常没有结果关系表.特例 SELECT INTO 几乎等于一个 CREATE TABLE, INSERT ... SELECT 序列,所以这里我们就不单独讨论了.

在 INSERT,UPDATE 和 DELETE 查询里, 结果关系(result relation )是更改发生影响的表(或视图!).

目标列 (target list)

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

DELETE 不需要目标列是因为它们不产生任何结果. 实际上规划器会向空目标列增加一条特殊的CTID记录. 但这是在规则系统之后并且我们将稍后讨论. 对于规则系统而言,目标列是空的.

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

在 UPDATE 查询里,它(目标列)描述应该替换旧行的新行. 在规则系统里,它只包含来自查询的 SET attribute = expression 部分抽取的表达式. 这时,规划器将通过插入从旧行抽取数据到新 行的表达式的方法处理缺失的字段. 并且它也会象 在 DELETE 里那样增加特殊的CTID记录.

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

条件 (qualification)

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

连接树

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

其他 (others)

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