PostgreSQL7.0手册-开发者手册 -61. PostgreSQL 内部概貌
.y 里的语法规则和动作为查询 一个简单的 Select 这个例子包含下面的简单查询,该查询将被用于随后各个阶段的各种描述和图片.这个查询假设在供应商数据库里的表已经定义了. select s.sname, se.pno from supplier s, sells se where s.sno > 2 and s.sno = se.sno; 构建的分析树(不带用于 where 子句的操作符树,它在图\ref{where_clause}里显示,因为在一幅图里没有足够的位置把两部分的数据结构都放进去)。
树的顶端节点是 SelectStmt 节点。对每个在 SQL 查询的 from子句里出现的元素创建一个 RangeVar 节点,存放 alias(别名)的名称和一个指向一个存放关系名称的RelExpr 节点的指针。所有 RangeVar 节点都收集到一个列表里,然后附加到 SelectStmt 节点的 fromClause 字段上。
对于 SQL 查询里面的 select列表 里出现的每个元素都创建一个 ResTarget 节点,存放一个指向 Attr 节点的指针。Attr 节点存放元素的关系名称和一个指向存放着字段名称的 Value 节点的指针。所有 ResTarget 节点都收集到一个列表里,然后链接到 SelectStmt 节点的 targetList 字段里。
图 \ref{where_clause} 显示了为例子 select s.sname, se.pno from supplier s, sells se where s.sno > 2 and s.sno = se.sno; 里 SQL 查询的 where 子句构建的操作符树,这个操作符树附加到了 SelectStmt 节点的字段 qual 上。操作符树的顶端节点是一个代表 AND 操作的 A_Expr 节点。这个节点有两个后继节点, lexpr 和 rexpr 分别指向两个子树。附加到 lexpr 的子树代表条件 s.sno > 2 而附加到 rexpr 的子树代表 s.sno = se.sno。为每个字段创建一个 Attr 节点,存放关系名和一个指向存放着字段名的 Value 节点的指针。为在查询里出现的常量条款创建一个 Const 节点,存放常量值。
转换处理
转换处理把分析器传递过来的分析树作为输入,然后递归地处理它。如果碰到一个 SelectStmt 节点,就把它转换成一个 Query 节点,这个节点将是新数据结构的最顶端节点。图 \ref{transformed} 显示了转换过后的数据结构(转换过后的 where 子句在图 \ref{transformed_where} 里给出,因为一幅图里放不下所有的部分)。
现在进行一个检查,看看 FROM 子句里面的关系名是否被系统所知。为每个系统表里面出现的关系名创建一个RTE 节点,该节点包含关系名,别名和关系 id。从现在开始,关系 id (标识)用于指代查询里出现的关系。所有RTE 节点都收集到范围表项目列表(range table entry list)里,然后该列表在链接到 Query 节点的 rtable 字段上。如果查询里面有一个不为系统所知的关系被检测到,那么将返回一个错误然后查询处理将退出。
下一步是检查所用的字段名是否包含在查询给出的关系里。为找到的每个字段创建一个TLE 节点,保存一个指向 Resdom 节点的(该节点里保存列名称)的指针和一个指向 VAR 节点的指针。在 VAR 节点里有两个重要的数字。数据域 varno 包含当前字段的关系在上面创建的范围表项目列表里面的位置。数据域 varattno 给出该字段在关系里的位置。如果无法找到一个字段的名称,则返回一个错误而且这个正在处理的查询将退出。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Postgres 规则系统
Postgres 维持一个强大的规则系统,用以阐述视图和不明确的视图更新。最初Postgres规则系统包含两个实现:
第一个能用的规则系统采用记录级别处理,是在执行器深层实现的。每次访问一条独立的记录时都调用规则系统。这个实现在1995年被删除了,那时Postgres 项目的最后一个官方版本正转换成 Postgres95。
第二个规则系统的实现从技术角度来说叫查询重写。重写系统是一个存在于分析器阶段和规划器/优化器之间的一个模块。这个技术实现仍然存在。
要获取关于 Postgres 系统里规则的创建和语法的信息,请参考 PostgreSQL 用户手册。
重写系统
重写系统是一个存在于分析器阶段和规划器/优化器之间的一个模块。它处理分析器阶段传回的分析树(该分析树代表用户查询),如果存在一条必须应用的规则的话,这个模块把分析树重写成一个变化了的形式。
实现视图的技巧
现在我们勾画一下查询重写系统的算法。为了更好的说明问题,我们把用规则系统实现视图作为一个例子。
先给出下面规则:
create rule view_rule
as on select
to test_view
do instead
select s.sname, p.pname
from supplier s, sells se, part p
where s.sno = se.sno and
p.pno = se.pno;
当检测到对关系 test_view 的 select 时,就会触发上面给出的规则。这时这句选择语句将执行规则里的动作部分,而不是从 test_view 里选择记录。
给出下面的用户对 test_view 的查询:
select sname
from test_view
where sname <> 'Smith';
这里是当一个用户查询作用于 test_view 时,查询重写系统执行的一系列步骤。(下面的列表只是一个非常不正式的关于查询重写的算法的描述,只是用于了解基础。更多的详细描述请参考 Stonebraker et al, 1989)。
test_view 重写
获取在规则的动作部分给出的查询。
调整其目标列表以便与用户查询给出的字段的数目和顺序相匹配。
把用户查询的 where 子句里的条件部分追加到规则动作部分的查询的条件上。
给出上面定义的规则后,用户查询将被重写为下面的形式(请注意:重写动作是对从分析器阶段传回的用户查询的内部形式操作的,不过所产生的新的数据结构将代表下面的查询):
select s.sname
from supplier s, sells se, part p
where s.sno = se.sno and
p.pno = se.pno and
s.sname <> 'Smith';
--------------------------------------------------------------------------------
---
树的顶端节点是 SelectStmt 节点。对每个在 SQL 查询的 from子句里出现的元素创建一个 RangeVar 节点,存放 alias(别名)的名称和一个指向一个存放关系名称的RelExpr 节点的指针。所有 RangeVar 节点都收集到一个列表里,然后附加到 SelectStmt 节点的 fromClause 字段上。
对于 SQL 查询里面的 select列表 里出现的每个元素都创建一个 ResTarget 节点,存放一个指向 Attr 节点的指针。Attr 节点存放元素的关系名称和一个指向存放着字段名称的 Value 节点的指针。所有 ResTarget 节点都收集到一个列表里,然后链接到 SelectStmt 节点的 targetList 字段里。
图 \ref{where_clause} 显示了为例子 select s.sname, se.pno from supplier s, sells se where s.sno > 2 and s.sno = se.sno; 里 SQL 查询的 where 子句构建的操作符树,这个操作符树附加到了 SelectStmt 节点的字段 qual 上。操作符树的顶端节点是一个代表 AND 操作的 A_Expr 节点。这个节点有两个后继节点, lexpr 和 rexpr 分别指向两个子树。附加到 lexpr 的子树代表条件 s.sno > 2 而附加到 rexpr 的子树代表 s.sno = se.sno。为每个字段创建一个 Attr 节点,存放关系名和一个指向存放着字段名的 Value 节点的指针。为在查询里出现的常量条款创建一个 Const 节点,存放常量值。
转换处理
转换处理把分析器传递过来的分析树作为输入,然后递归地处理它。如果碰到一个 SelectStmt 节点,就把它转换成一个 Query 节点,这个节点将是新数据结构的最顶端节点。图 \ref{transformed} 显示了转换过后的数据结构(转换过后的 where 子句在图 \ref{transformed_where} 里给出,因为一幅图里放不下所有的部分)。
现在进行一个检查,看看 FROM 子句里面的关系名是否被系统所知。为每个系统表里面出现的关系名创建一个RTE 节点,该节点包含关系名,别名和关系 id。从现在开始,关系 id (标识)用于指代查询里出现的关系。所有RTE 节点都收集到范围表项目列表(range table entry list)里,然后该列表在链接到 Query 节点的 rtable 字段上。如果查询里面有一个不为系统所知的关系被检测到,那么将返回一个错误然后查询处理将退出。
下一步是检查所用的字段名是否包含在查询给出的关系里。为找到的每个字段创建一个TLE 节点,保存一个指向 Resdom 节点的(该节点里保存列名称)的指针和一个指向 VAR 节点的指针。在 VAR 节点里有两个重要的数字。数据域 varno 包含当前字段的关系在上面创建的范围表项目列表里面的位置。数据域 varattno 给出该字段在关系里的位置。如果无法找到一个字段的名称,则返回一个错误而且这个正在处理的查询将退出。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Postgres 规则系统
Postgres 维持一个强大的规则系统,用以阐述视图和不明确的视图更新。最初Postgres规则系统包含两个实现:
第一个能用的规则系统采用记录级别处理,是在执行器深层实现的。每次访问一条独立的记录时都调用规则系统。这个实现在1995年被删除了,那时Postgres 项目的最后一个官方版本正转换成 Postgres95。
第二个规则系统的实现从技术角度来说叫查询重写。重写系统是一个存在于分析器阶段和规划器/优化器之间的一个模块。这个技术实现仍然存在。
要获取关于 Postgres 系统里规则的创建和语法的信息,请参考 PostgreSQL 用户手册。
重写系统
重写系统是一个存在于分析器阶段和规划器/优化器之间的一个模块。它处理分析器阶段传回的分析树(该分析树代表用户查询),如果存在一条必须应用的规则的话,这个模块把分析树重写成一个变化了的形式。
实现视图的技巧
现在我们勾画一下查询重写系统的算法。为了更好的说明问题,我们把用规则系统实现视图作为一个例子。
先给出下面规则:
create rule view_rule
as on select
to test_view
do instead
select s.sname, p.pname
from supplier s, sells se, part p
where s.sno = se.sno and
p.pno = se.pno;
当检测到对关系 test_view 的 select 时,就会触发上面给出的规则。这时这句选择语句将执行规则里的动作部分,而不是从 test_view 里选择记录。
给出下面的用户对 test_view 的查询:
select sname
from test_view
where sname <> 'Smith';
这里是当一个用户查询作用于 test_view 时,查询重写系统执行的一系列步骤。(下面的列表只是一个非常不正式的关于查询重写的算法的描述,只是用于了解基础。更多的详细描述请参考 Stonebraker et al, 1989)。
test_view 重写
获取在规则的动作部分给出的查询。
调整其目标列表以便与用户查询给出的字段的数目和顺序相匹配。
把用户查询的 where 子句里的条件部分追加到规则动作部分的查询的条件上。
给出上面定义的规则后,用户查询将被重写为下面的形式(请注意:重写动作是对从分析器阶段传回的用户查询的内部形式操作的,不过所产生的新的数据结构将代表下面的查询):
select s.sname
from supplier s, sells se, part p
where s.sno = se.sno and
p.pno = se.pno and
s.sname <> 'Smith';
--------------------------------------------------------------------------------
---

