1、第四章 查询优化,查询处理概述(1),关系操作是非过程化的,其存取路径对用户透明。用户只需说明“干什么”,不必指出“怎么干”。 输入:SQL语句 输出:操作的结果,查询处理概述(2),对于关系数据库系统,查询优化是: 挑战:必须进行好的优化,才有可接受的性能 机会:关系表达式的语义层次高,提供了优化的可能性。,查询处理概述(3),相对于由用户选择存取路径的方式: 降低了对用户的要求,方便了用户的使用。避免了因用户选择了错误的存取路径而导致的效率低下。 能够取得更好的优化效果,因为 优化器具有丰富的可使用的信息 当数据库发生变化时优化器容易再次进行优化 优化器能够对多种实现策略逐一进行考虑 优化
2、器集中了最优秀的程序员的智慧和经验,查询处理概述(4),查询处理的基本步骤: 语法分析与翻译 优化 执行查询语句,查询处理概述(5),查询优化,查询优化是为关系代数表达式的计算选择最有效的查询计划的过程。 查询优化的过程: 代数优化:力图找出与给定关系代数表达式等价的但执行效率更高的一个表达式。 物理优化:查询语句处理的详细策略的选择,例如选择执行运算所采用的具体算法,选择将使用的特定索引等等。,查询优化的步骤,将查询转换成某种内部表示,通常是语法树。 根据一定的变换规则,把语法树转换为优化形式。 选择低层的操作算法。 生成查询执行计划(也称查询执行方案,是由一系列内部操作构成的)。,查询代价
3、的度量(1),查询代价:查询处理对各种资源的使用情况 总代价=I/O代价+CPU代价+通信开销 I/O代价的度量方式: I/O块数或者I/O的次数,查询代价的度量(2),一个重要的影响因素:主存中缓冲区的大小M 最好的情形,所有的数据可以读入到缓冲区中 最坏的情形,缓冲区只能容纳数目不多的数据块大约每个关系一块。,基本运算的实现,每一基本的代数运算都有多种不同的实现算法。 适用于不同的情况 等值条件,范围条件 数据是聚集的,数据是非聚集的 相关属性上有索引,相关属性上没有索引 执行代价不同,选取运算的实现算法(1),全表扫描方法:依次访问表的每一个块,对于每一个元组,测试它是否满足选择条件。效
4、率低,但对关系的存储方式没有要求,不需要索引。适用于任何选择条件。 折半扫描: 对于按某一属性排序的文件,且选择条件是该属性上的等值比较方法,可以使用折半的方法扫描文件。效率高,但需要有序文件,选取运算的实现算法(2),索引扫描:对于在选择条件的属性上建有索引的表,可以采用访问索 引,根据索引项的指示去访问数据元组的方法。 无序索引:访问满足等值条件的元组 有序索引:访问满足范围查找条件的一系列元组。,查询优化的必要性(1),例:求选修了课程2的学生姓名 SELECT Student.Sname FROM Student, SC WHERE Student.Sno=SC.Sno AND SC.
5、Cno=2;,查询优化的必要性(2),查询优化的必要性(3),假设: Student表中有1000条学生记录:nstudent= 1000 SC表中有10000条选课记录: nsc= 10000 其中选修2号课程的选课记录为50条: SC(cno,SC)=50 一个块可以装10个Student元组或100个SC元组:fstudent= 10,fSC= 100 Student表占用的块: bstudent= 100 SC表占用的块:bSC= 100,查询优化的必要性(4),一个块可以装10个Student和SC的连接结果元组:fjoin= 10 缓冲: 内存中一次可以存放5块Student元组、
6、1块SC元组和若干块连接结果元组 读写速度:20块/秒,查询优化的必要性(5),读数据时间=2100/20=105秒,查询优化的必要性(6),查询优化的必要性(7),查询优化的必要性(8),查询优化的一般准则(1),选择运算应尽可能先做。目的:减小中间关系。 在执行连接操作前对文件适当进行预处理 排序 在连接属性上建立索引 投影运算和选择运算同时做。目的:避免重复扫描关系。 把投影运算与其前面或后面的双目运算结合起来。目的:减少扫描关系的遍数。,查询优化的一般准则(2),某些选择运算在其前面执行的笛卡尔积 连接运算找出公共子表达式,表达式的等价性,两个表达式等价:产生的结果关系具有相同的属性集
7、和相同的元组集。,关系代数等价变换规则(1),所谓关系代数表达式的等价是指用相同的关系代替两个表达式中相应的关系所得到的结果是相同的。上面的优化策略大部分都涉及到代数表达式的变换。,关系代数等价变换规则(2),关系代数等价变换规则(3),关系代数等价变换规则(4),关系代数等价变换规则(5),关系代数等价变换规则(6),关系代数等价变换规则(7),关系代数等价变换规则(8),关系代数等价变换规则(9),关系代数等价变换规则(10),变换规则小结,1-2: 连接、笛卡尔积的交换律、结合律 3: 合并或分解投影运算 4: 合并或分解选择运算 5-8:选择运算与其他运算交换 5,9,10: 投影运算
8、与其他运算交换,查询树,查询树 - 关系代数表达式的树形表示. 输入关系查询树的叶节点 关系操作 内部节点 从底向上执行,例子(1),一个未优化的关系代数表达式,例子(2),初始查询树,例子(3),规则1:尽可能早地进行选取操作,例子(4),规则2:使用连接操作替代笛卡尔积,例子(5),规则3:首先执行产生较小结果集的连接,例子(6),规则4:将没有用的属性利用投影操作去掉,性能优化,数据库性能是由多个因素所构成的: 正确性(事务完整性和数据完整性) 可用性 响应时间 性能优化的工作是从项目的第一天就开始的。对数据库性能影响最大的是数据库的设计和开发。通常,所谓的性能优化实际上就是重新开发数据
9、库系统中设计的很糟的那一部分。,优化准则,花费尽可能多的努力来设计数据库模式,所有的优化都要基于数据库模式。集中精力优化运行最频繁的代码,而不是那些运行最慢的代码。在升级硬件之前进行优化。即使在速度快的服务器上,坏代码仍旧是坏代码。,优化准则,列出所有可能的优化思路,即使你没有时间在现在去实施它们。新特性会与优化竞争资源;因此,最好的办法是开发一个维持现有功能,但提高了性能的版本。优化是一个研究与探索的过程,你很难对它做出预测。所以,最好不要对优化的效果或交付日期做出承诺。,优化准则,以索引的形式列出系统中那些易于修改和优化的部分。 集中精力修改应用程序中性能最坏的部分。 花费一些时间作为用户
10、使用应用程序。去使用该程序的部门工作上一个星期,这将会使你产生很多有价值的灵感。,负载测试,数据负载测试 只有当数据量超出了服务器内存容量好几倍的时候,才能够对数据库模式和查询进行负载测试。 用户负载测试 只有当使用大量的用户来测试数据库时才有可能发生锁争用,而锁争用会导致严重的性能问题。,负载测试,清除测试的影响 数据库已经经过优化,它可以智能地将数据缓存在内存中,而这将会影响到后续测试的结果。因此,测试前要刷新内存,这可以通过停止并重新启动服务器实现。,影响性能的因素,规范化的数据库物理模式设计 完善的和平衡的索引策略 使用基于集合的查询方式编码,并避免以过程化(基于行的方式)来操作数据
11、使用数据库约束和触发器来实施业务规则 精心地设计表、索引和代码以避免锁争用,数据库设计与性能,将数据库规范化到第三范式,随后精心地实施使用高性能的、单列主键的物理设计。 不要过度地规范化数据库,或者说使数据库过度复杂化,而应当坚持不懈地努力,直至找到简单而优雅的数据库设计为止。 避免要以事务的方式在表和表之间来回倒数据的数据库设计。,数据库设计与性能,如果要使用代码来创建多个临时表或者额外的工作表,那就说明数据库的设计是不充分的。 在设计数据库模式的时候,必须考虑那些基于它的查询。 必要的时候,要勇敢地将数据从OLTP表复制到非规范化的、只读的表中去,以便加快数据库的读速度。,约束和触发器,要
12、在数据库级实施规则,以便能够快速地执行这些规则,并保证在任何情况下都无法避开这些规则的检查。 用数据库约束来实施数据库规则和业务规则,对于那些无法用数据库约束来实施的规则,再使用触发器来实施。 触发器必须使用基于集合的DML语句,而不要使用游标。因为每一个insert、update或者delete操作都会触发触发器,所以在优化触发器的代码时应当加倍地努力。,查询设计和性能,争取重用查询执行计划。 只使用视图支持复杂的用户查询,除此之外从不在代码中使用视图。 使用子查询将庞大而复杂的查询分解为多个更小的逻辑单元。,哪些查询不能利用索引,使用AND连接到一起的多个条件可以利用索引,使用OR连接在一
13、起的多个条件则不能。否定的搜索条件(、!、!、Not Exists、Not In、Not Like)是不可优化的。因为证明一行是存在的很容易,可是如果要证明一行是不存在的,就需要检查每一行。 由通配符开始的条件是不能使用索引的。 使用了表达式的条件也不能使用索引。 如果where子句包含了函数(例如字符串函数),就需要使用表扫描,以便可以使用函数来测试每个行中的数据。,均衡的索引策略,基础索引,将每一个主键都作为非聚集索引来创建。这是因为主键通常用于单行检索。为每个表创建一个聚集索引。对于主表,应当在那些最常用来排序的列上建立聚集索引。但应当注意不要在主键上建立聚集索引。对于从表,应当为最重要
14、的外部键创建聚集索引。除了在第二步中已经为其创建了索引的外部键以外,对于每个外部键中的那些列创建非聚集索引。对于where子句或者order by子句中所引用的每个列创建单列索引。,索引调优,索引字段应当包含足够多的不同的值 表较大,但大多数的查询只会查找其中24的记录行 并非索引越多,效率就会越好 平衡查询和DML操作的要求 创建复合索引时,应注意索引字段的顺序。使用复合索引的一种好方法是:通过在复合索引中包含所有需要的列来消除数据页读操作。 注意消除重复索引。,加锁和性能,检查事务的隔离级别,并确保它没有高于所需要的级别。 确保快速地启动和提交事务。重新设计所有包含游标的事务。 如果两个程序有可能会死锁,应当确保它们按照同样的顺序对资源进行锁定。 确保客户应用程序在获取数据之后立即释放所有的锁。,