受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

Chapter 39. 规则系统

本章讨论PostgreSQL中的规则系统。产生式规则系统在概念上很简单,但在实际使用时涉及许多微妙之处。

有些其他数据库系统定义了主动型数据库规则,它们通常表现为存储过程和触发器。在PostgreSQL中,这类功能同样可以用函数和触发器实现。

规则系统(更准确地说,查询重写规则系统)与存储过程和触发器完全不同。它会修改查询,使其将规则纳入考虑,然后把修改后的查询交给查询规划器进行规划和执行。它非常强大,可用于查询语言过程、视图和版本等许多用途。关于这一规则系统的理论基础及其能力,另见[ston90b][ong90]

39.1. 查询树 #

要理解规则系统如何工作,必须先知道它在何时被调用,以及它的输入和输出是什么。

规则系统位于解析器和规划器之间。它接收解析器的输出,即一棵查询树,以及用户定义的重写规则;这些规则本身也是带有一些附加信息的查询树。它会生成零棵或多棵查询树作为结果。因此,它的输入和输出始终都是解析器本身也可能产生的东西,所以它看到的任何内容基本上都可以表示为一个SQL语句。

那么什么是查询树?它是SQL语句的一种内部表示,其中构成语句的各个部分被分别存储。如果你设置了配置参数debug_print_parsedebug_print_rewrittendebug_print_plan,这些查询树就可以显示在服务器日志中。规则动作也以查询树的形式存储在系统目录pg_rewrite中。它们的格式不像日志输出,但包含的却是完全相同的信息。

阅读原始查询树需要一些经验。但由于查询树的SQL表示已足以理解规则系统,本章不会讲解如何阅读它们。

在阅读本章中查询树的SQL表示时,必须能够识别语句在查询树结构中被拆分成的各个部分。查询树的组成部分有:

命令类型 #

这是一个简单的值,用来说明是哪一种命令(SELECTINSERTUPDATEDELETE)产生了该查询树。

范围表 #

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

每个范围表项标识一个表或视图,并说明在查询的其他部分以哪个名称来称呼它。在查询树中,范围表项是按编号而不是按名称引用的,因此即使像SQL语句中那样出现重名,这里也无关紧要。这种情况可能出现在规则的范围表被合并之后。本章中的示例不会涉及这种情形。

结果关系 #

这是范围表中的一个索引,用来标识查询结果应写入哪个关系。

SELECT查询没有结果关系。(SELECT INTO这一特殊情况与CREATE TABLE后接INSERT ... SELECT几乎相同,这里不再单独讨论。)

对于INSERTUPDATEDELETE命令,结果关系就是要让修改生效的表(或视图!)。

目标列表 #

目标列表是定义查询结果的表达式列表。对于SELECT,这些表达式构成查询的最终输出。它们对应于关键字SELECTFROM之间的表达式。(*只是某个关系全部列名的缩写。解析器会把它展开为各个独立列,因此规则系统永远不会看到它。)

DELETE命令不需要普通的目标列表,因为它们不产生任何结果。相反,规划器会向空目标列表加入一个特殊的CTID项,以便执行器找到要删除的行。(当结果关系是普通表时,会加入CTID;如果结果关系是视图,则规则系统会改为加入一个整行变量,如Section 39.2.4所述。)

对于INSERT命令,目标列表描述的是将要进入结果关系的新行。它由VALUES子句中的表达式,或INSERT ... SELECTSELECT子句中的表达式组成。重写过程的第一步会为原始命令未赋值但带有默认值的列补上目标列表项。其余列(既没有给定值也没有默认值)将由规划器填入常量空值表达式。

对于UPDATE命令,目标列表描述要替换旧行的新行。在规则系统中,它只包含命令中SET column = expression部分的表达式。规划器会通过插入把旧行值复制到新行的表达式来处理缺失列。与DELETE一样,还会加入一个CTID或整行变量,以便执行器标识要更新的旧行。

目标列表中的每一项都包含一个表达式,它可以是常量值、指向范围表中某个关系列的变量、一个参数,或者由函数调用、常量、变量、操作符等构成的表达式树。

条件 #

查询的条件是一个表达式,与目标列表项中的表达式很相似。该表达式的结果值是布尔值,用来说明是否应对最终结果行执行相应操作(INSERTUPDATEDELETESELECT)。它对应于SQL语句的WHERE子句。

连接树 #

查询的连接树显示了FROM子句的结构。对于SELECT ... FROM a, b, c这样的简单查询,连接树只是FROM项的一个列表,因为允许按任意顺序连接它们。但当使用JOIN表达式,特别是外连接时,就必须按连接所显示的顺序进行连接。在这种情况下,连接树展示的是JOIN表达式的结构。与特定JOIN子句相关的限制(来自ONUSING表达式)会作为条件表达式附着在相应的连接树节点上。把顶层WHERE表达式也存储为附着在顶层连接树项上的一个条件,会很方便。因此,连接树实际上同时表示SELECTFROMWHERE子句。

其他 #

查询树的其他部分,如ORDER BY子句,这里不作关注。规则系统在应用规则时会替换其中某些项,但这与规则系统的基本原理关系不大。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。