第九章——关系查询处理和查询优化

  • 本章介绍关系数据库的查询处理(query processing)和查询优化(query optimization)技术
  • 查询优化一般可分为代数优化(也称为逻辑优化)和物理优化(也称为非代数优化)。
  • 代数优化是指关系代数表达式的优化,物理优化则是指通过存取路径和底层操作算法的选择进行的优化。

关系数据库系统的查询处理

  • 查询处理是关系数据库管理系统执行查询语句的过程,其任务是把用户提交给关系数据库管理系统的查询语句转换为高效的查询执行计划

查询处理步骤

  • 关系数据库管理系统查询处理可以分为4个阶段:查询分析、查询检查、查询优化和查询执行。
    第九章——关系查询处理和查询优化_第1张图片
  1. 查询分析
  • 首先对查询语句进行扫描、词法分析和语法分析。从查询语句中识别出语言符号,如SQL关键字、属性名和关系名等,进行语法检查和语法分析,即判断查询语句是否符合SQL语法规则。如果没有语法错误就转入下步处理,否则便报告语句中出现的语法错误。
  1. 查询检查
  • 对合法的查询语句进行语义检查,即根据数据字典中有关的模式定义检查语句的数据库对象,如关系名、属性名是否存在和有效。如果是对试图的操作,则要用试图消解方法把对视图的操作转换成对基本表的操作。还要根据数据字典中的用户权限和完整性约束定义对用户的存取权限进行检查。如果该用户没有相应的访问权限或违反了完整性约束,就拒绝执行该查询。当然,这时的完整性检查是初步的、静态的检查。检查通过后便把SQL查询语句转换成内部表示,即等价的关系代数表达式。这个过程中要把数据库对象的外部名称转换为内部表示。关系数据库管理系统一般都用查询树(query tree),也称为语法分析树(syntax tree)来表示扩展的关系代数表达式。
  1. 查询优化
  • 每个查询都会有许多可供选择的执行策略和操作算法,查询优化就是选择一个高效执行的查询处理策略。按照优化的层次一般可将查询优化分为代数优化物理优化。代数优化是指关系代数表达式的优化,即按照一定的规则,通过对关系代数表达式进行等价变换,改变代数表达式中操作的次序和组合,使查询执行更高效;物理优化是指存取路径和底层操作算法的选择。选择的依据可以是基于规则(rule based)的,也可以是基于代价的(cost based)的,还可以是基于语义(semantic based)的。
  1. 查询执行
  • 依据优化器得到的执行策略生成查询执行计划,由代码生成器(code generator)生成执行这个查询计划的代码,然后加以执行,回送查询结果。
  • 两种执行方法:自顶向下和自底向上

实现查询操作的算法实例

选择操作的实现

  • SELECT语句的功能强大,有许多选项,因此实现的算法和优化策略也很复杂。
  • 选择操作只涉及一个关系,一般采用全表扫描或者基于索引的算法

(1)简单的全表扫描算法(table scan)

  • 假设可以使用的内存为M块,全表扫描的算法思想如下:
    ①按照物理次序读Student的M块到内存
    ②检查内存的每个元组t,如果t满足选择条件,则输出t
    ③如果Student还有其他块未被处理,重复①和②
  • 全表扫描算法只需要很少的内存(最少为1块)就可以运行,而且控制简单。对于规模小的表,这种算法简单有效。对于规模大的表进行顺序扫描,当选择率(即满足条件的元组数占全表的比例)较低时,这个算法效率很低。

(2)索引扫描算法(index scan)

  • 如果选择条件中的属性上有索引(例如B+树索引或hash索引),可以用索引扫描方法,通过索引先找到满足条件的元组指针,再通过元组指针在查询的基本表中找到元组。
  • 一般情况下,当选择率较低时,基于索引的选择算法要优于全表扫描算法。但在某些情况下,例如选择率较高,或者要查找的元组均匀分布再查找的表中,这时基于索引的选择算法的性能不如全表扫描算法。因为除了对表的扫描操作,还要加上B+树索引的扫描操作,对每一个检索码,从B+树根结点到叶子结点路径上的每个结点都要执行一个I/O操作。

连接操作的实现

  • 连接操作是查询处理中最常用也是最耗时的操作之一。

(1)嵌套循环算法(nested loop join)

  • 这是最简单可行的算法。对外层循环的每一个元组,检索内层循环中的每一个元组,并检查这两个元组在连接属性上是否相等。如果满足条件,则串接后作为结果输出,直到外层循环表中的元组处理完为止。

(2)排序—合并算法(sort-merge join或merge join)

  • 这是等值连接常用的算法,尤其适合参与连接的诸表已经排好序的情况。
  • 用排序—合并连接算法的步骤是:
    ①参与连接的表,首先对这些表按连接属性排序;
    ②对表一中每个元素,依次扫描表二中具有相同连接属性的元组,将他们连接;
    ③当扫描到第一个不相同的元组时,返回并选择表一的下一个元素,继续执行上述操作;
  • 如果两个表原来无序,执行时间要加上对两个表的排序时间。一般来说,对于大表,先排序后使用排序—合并连接算法执行连接,总的时间一般仍会减少。

(3)索引连接(index join)算法

(4)hash join算法

  • hash join算法也是处理等值连接的算法。它把连接属性作为hash码,用同一个hash函数把表一和表二的元组散列到hash表中。
    划分阶段(building phase),也称创建阶段,即创建hash表。对包含较少元组的表进行一遍处理,把它的元组按hash函数分散到hash表的桶中;
    试探阶段(probing phase),也称连接阶段,对另一个表进行一遍处理,把该表的元组也按同一个哈希函数进行散列,找到合适的hash桶,并把该元组与桶中来自表一的元组连接起来。

关系数据库系统的查询优化

  • 关系查询优化是影响关系数据库管理系统性能的关键因素。
  • 优化对关系系统来说既是挑战又是机遇。所谓挑战是指关系系统为了达到用户可接受的性能必须进行查询优化;而机遇在于关系数据库可以从关系表达式中分析查询语义,提供了执行查询优化的可能性,这也是关系系统在性能上能够接近甚至超过非关系系统的原因。

查询优化概述

  • 关系系统的查询优化既是关系数据库管理系统实现的关键技术,又是关系系统的优点所在。它减轻了用户选择存取路径的负担,用户只要提出"干什么",而不必指出"怎么干"。对比一下非关系系统中的情况:用户使用过程化的语言表达查询要求,至于执行何种记录级的操作,以及操作的序列是由用户而不是由系统来决定的。因此用户必须了解存取路径,系统要提供用户选择存取路径的手段,查询效率由用户的存取策略决定。如果用户做了不当的选择,系统是无法对此加以改进的。
  • 查询优化的优点不仅在于用户不必考虑如何最好地表达查询以获得较好的效率,而且在于系统可以比用户程序的"优化"做得更好。这是因为:

(1)优化器可以从数据字典中获取许多统计信息,例如每个关系表中元组数、关系中每个属性值的分布情况、哪些属性上以及建立了索引等。优化器可以根据这些信息做出正确的估算,选择高效的执行计划,而用户程序则难以获得这些信息。
(2)如果数据库的物理统计信息改变了,系统可以自动对查询进行重新优化以选择相适应的执行计划。在非关系系统中必须重 写程序,而重写程序在实际应用中往往是不太可能的。
(3)优化器可以考虑数百种不同的执行计划,而程序员则一般只能考虑有限的几种可能性。
(4)优化器中包含了很多复杂的优化技术,这些优化技术往往只有最好的程序员才能掌握。系统的自动优化使得所有人都拥有这些优化技术。

  • 目前关系数据库管理系统通过某种等价模型计算出各种查询执行策略的执行代价,然后选取代价最小的执行方案。在集中式数据库中,查询执行开销主要包括磁盘存取块数(I/O)代价、处理机时间(CPU代价)以及查询的内存开销。在分布式数据库中还要加上通信代价,即:总代价=I/O代价+CPU代价+内存代价+通信代价
  • 由于磁盘I/O操作涉及机械动作,需要的时间与内存操作相比要高几个数量级,因此,在计算查询代价时一般用查询处理读写的块数作为衡量单位。
  • 查询优化的总目标是选择有效的策略,求得给定关系表达式的值,使得查询代价较小。因为查询优化的搜索空间有时非常大,实际系统选择的策略不一定是最优的,而是较优的。

代数优化

关系代数表达式等价变换规则

  • 代数优化策略是通过对关系代数表达式的等价变换来提高查询效率。所谓关系代数表达式的等价是指用相同的关系代替两个表达式中相应的关系所得到的结果是相同的。两个关系表达式 E 1 E_1 E1 E 2 E_2 E2是等价的,可记为 E 1 ≡ E 2 E_1≡E_2 E1E2
  • 连接、笛卡尔积的交换律
  • 连接、笛卡尔积的结合律
  • 投影的串接定律
  • 选择的串接定律
  • 选择与投影操作的交换律
  • 选择与笛卡尔积的交换律
  • 选择与并的分配律
  • 选择与差运算的分配律
  • 选择对自然连接的分配律
  • 投影与笛卡尔积的分配律
  • 投影与并的分配律

查询树的启发式优化

  • 启发式规则(heuristic rules)的代数优化是对关系代数表达式的查询树进行优化的方法。
  • 典型的启发式规则有:
    (1)选择运算应尽可能先做
    (2)把投影运算和选择运算同时进行
    (3)把投影同其前或后的双目运算结合起来
    (4)把某些选择同在它前面要执行的笛卡尔积结合起来成为一个连接运算
    (5)找出公共子表达式

物理优化

  • 代数优化改变查询语句中操作的次序和组合,但不涉及底层的存取路径。对每一种操作有多种执行这个操作的算法,有多条存取路径,因此对于一个查询语句有许多存取方案,它们的执行效率不同,有的会相差很大。因此,仅仅进行代数优化是不够的。
  • 物理优化就是要选择高效合理的操作算法或存取路径,求得优化的查询计划,达到查询优化的目标。
  • 选择的方法可以是:
    (1)基于规则的启发式优化
    (2)基于代价估算的优化
    (3)两者结合的优化方式

基于启发式规则的存取路径选择优化

  1. 选择操作的启发式规则
  • 对于小关系,使用全表顺序扫描,即使选择列上有索引
  • 对于大关系,启发式规则有:

(1)对于选择条件是"主码=值"的查询,查询结果最多是一个元组,可以选择主码索引。一般的关系数据库管理系统会自动建立主码索引。
(2)对于选择条件是"非主属性=值"的查询,并且选择列上有索引,则要估算查询结果的元组数目,如果比例较小(<10%)可以使用索引扫描方法,否则还是使用全表顺序扫描
(3)对于选择条件是属性上的非等值查询或者范围查询,并且选择列上有索引,同样要估算查询结果的元组数目,如果选择率<10%可以使用索引扫描方法,否则还是使用全表顺序扫描
(4)对于用AND连接的合取选择条件,如果有涉及这些属性的组合索引,则优先采用组合索引扫描方法
(5)对于用OR连接的析取选择条件,一般使用全表顺序扫描

  1. 连接操作的启发式规则
    (1)如果2个表都已经按照连接属性排序,则选用排序-合并算法
    (2)如果一个表在连接属性上有索引,则可以选用索引连接算法
    (3)如果上面2个规则都不适用,其中一个表较小,则可以选用hash join算法
    (4)最后可以选用嵌套循环算法,并选择其中较小的表,确切地讲是占用的块数(B)较少的表,作为外表(外循环的表)

基于代价估算的优化

  • 启发式规则优化是定性的选择,比较粗糙,但是实现简单且优化本身代价较小,适合解释执行的系统。因为解释执行的系统,其优化开销包含在查询总开销之中。在编译执行的系统中,一次编译优化,多次执行,查询优化和查询执行是分开的。因此,可以采用精细复杂一些的基于代价的优化方法。
  • 基于代价的优化方法要计算各种操作算法的执行代价,它与数据库的状态密切相关。为此在数据字典中存储了优化器需要的统计信息(database statistics),主要包括如下几个方面:
    (1)基本表:该表的元组总数(N)、元组长度(l)、占用的块数(B)、占用的溢出块数(B O)等。
    (2)基本表每个列:该列不同值的个数(m)、该列最大值、最小值,该列上是否已经建立了索引,是哪种索引(B+树索引、hash索引、聚集索引)。根据这些统计信息,可以计算出谓词条件的选择率(f),如果不同值的分布均匀,f=1/m;如果不同值的分布不均匀,则要计算每个值的选择率,f=具有该值的元组数/N。
    (3)索引:例如B+树索引,索引的层数(L)、不同索引值的个数、索引的选择基数S(有S个元组具有某个索引值)、索引的叶结点数(Y)。

查询计划的执行

  • 查询优化完成后,关系数据库管理系统为用户查询生成了一个查询计划。该查询计划的执行可以分为自顶向下和自底向上两种执行方法。
  • 自顶向下的执行方式中,系统反复向查询计划顶端的操作符发出需要查询结果元组的请求,操作符收到请求后,就试图计算下一个(几个)元组并返回这些元组。在计算时,如果操作符的输入缓冲区为空,它就会向其孩子操作符发送需求元组的请求…这种需求元组的请求会一直传到叶子结点,启动叶子操作符运行,并返回其父操作符一个(几个)元组,父操作符再计算自己的输出返回给上层操作符,直至顶端操作符。重复这一过程,直到处理完整个关系。
  • 自底向上的执行方式中,查询计划从叶结点开始执行,叶结点操作符不断地产生元组并将它们放入其输出缓冲区中,直到缓冲区填满为止,这时它必须等待其父操作符将元组从该缓冲区中取走才能继续执行。然后其父结点操作符开始执行,利用下层的输入元组来产生它自己的输出元组,直到其输出缓冲区满为止。这个过程不断重复,直到产生所有的输出元组。
  • 显然,自顶向下的执行方式是一种被动的、需求驱动的执行方式。而自底向上的执行方式是一种主动的执行方式。

你可能感兴趣的:(数据库系统概论,数据库,代数优化,物理优化)