查询优化分为:代数优化(逻辑优化)和物理优化(非代数优化)。
1. 代数优化:关系代数表达式的优化
2. 物理优化:通过存取路径和底层操作算法的选择进行的优化。
查询处理是关系数据库管理系统执行查询语句的过程,其任务是把用户提交给关系数据库管理系统的查询语句转为高效的查询执行计划。
一、查询处理步骤
1. 查询分析
对查询语句进行扫描、词法分析和语法分析。从查询语句中识别出语言符号,进行语法检查和语法分析,即判断查询语句是否符合SQL语法规则,如果没有语法错误就转入下步处理,否则便报告语句中出现的语法错误。
2. 查询检查
对合法的查询语句进行语义查询,即根据数据字典中有关的模式定义检查语句中的数据库对象(关系名、属性名)是否存在和有效。如果是对视图的操作,要用视图消解方法把对视图的操作转换成对基本表的操作。还要根据数据字典中的用户权限和完整性约束定义对用户的存取权限进行检查。如果对该用户没有相应的防伪权限或违反了完整性约束,就拒绝执行该查询。当然,这时的完整性检查是初步、静态的检查。检查通过后便把SQL查询语句转换成内部表示,即等价的关系代数表达式。这个过程中要把数据库对象的外部名称转换为内部表示。关系数据库管理系统一般都用查询树,也称为语法分析树来表示扩展的关系代数表达式。
查询处理步骤图示:
3. 查询优化
每个查询都会有许多可供选择的执行策略和操作算法,查询优化就是选择一个高效执行的查询处理策略。
按照优化的层次:
1. 代数优化
指关系代数表达式的优化。按照一定的规则,通过对关系代数表达式进行等价变换,改变代数表达式中操作的次序和组合,使查询执行更高效。
2. 物理优化
指存取路径和底层操作算法的选择。选择的依据可以是基于规则的,也可以是基于代价的,还可以是基于语义的。
4. 查询执行
依据优化器得到的执行策略生成查询执行计划,由代码生成器生成执行这个查询计划的代码,然后加以执行,回送查询结果。
二、实现查询操作的算法
1. 选择操作的实现
select * from table where <条件表达式 >
选择操作只涉及一个关系,一般采用全表扫描或者基于索引的算法。
1. 简单的全表扫描算法
假设可以使用的内存为M块,则:
a. 按照物理次序读Table的M块到内存。
b. 检查内存的每个元组t,如果t满足条件,则输出t。
c. 如果table还有其他块未处理,重复a 和 b。
全表扫描算法只需要很少的内存就可以运行,而且控制简单。
2. 索引扫描算法
如果选择条件中的属性上有索引(B+树或hash索引),通过索引先找到满足条件的元组指针,再通过元组指针在查询的基本表中找到元组。
当选择效率较低时,基于索引的选择算法要优于全表扫描算法。但选择率较高或者要查找的元组均分在查找表中,全表扫描法的性能就会比较高。
2. 连接操作的实现
连接操作是查询处理中最常用也是最耗时的操作之一。
select * from table1,table2 where table1.id = table2.tid
1. 嵌套循环(nested loop join)算法
对外层循环(table1)的每一个元组,检索内层循环中(table2)的每一个元组,并检查两个元组在连接属性上是否相等。如果连接条件满足,则串接后作为结果输出,直到外层循环表中的元组处理完为止。
2. 排序-合并(sort-merge join)算法
这是等值连接常用的算法,尤其适合参与连接的诸表已经排好序的情况。
1) 如果参与连接的表没有排好序,首先对table1和table2按连接属性id和tid进行排序。
2)取table1中的第一个id,依次扫描table2中具有相同tid的元组,把它们连接起来。
3)当扫描到id不相同的第一个table2元组时,返回table1表扫描它的下一个元组,再扫描table2表中具有相同id的元组进行连接。
3. 索引连接(index join)算法
1)在table2上已经建立了属性tid的索引。
2)对table1中每一个元组,由id值通过table2的索引查找相应的table2元组。
3)把这些table12元组和table1表中的元组连接起来。
循环执行2)和3),直到table1中的元组处理完为止。
4. hash join算法
它把连接属性作为hash码,用同一个hash函数把两张表中的元组散列到hash表中。
1)划分阶段(创建阶段)
创建hash表,对包含较少元组的表进行一遍处理,把它的元组按hash函数(hash码是连接属性)分散到hash表中的桶中。
2)试探阶段(连接阶段)
对另一个表进行一遍处理,把table2表的元组也按同一个hash进行散列,找到适当的hash桶,并把table2元组与桶中来自table1并与之相匹配的元组连接起来、