您的位置:首页 > 数据库

通过分析SQL语句的执行计划优化SQL(三)

2008-04-30 05:58 706 查看
四:ORACLE的优化器

优化器有时也被称为查询优化器,这是因为查询是影响数据库性能最主要的部分,不要以为只有SELECT语句是查询。实际上,带有任何WHERE条件的DML(INSERT、UPDATE、DELETE)语句中都包含查询要求,在后面的文章中,当说到查询时,不一定只是指SELECT语句,也有可能指DML语句中的查询部分。优化器是所有关系数据库引擎中的最神秘、最富挑战性的部件之一,从性能的角度看也是最重要的部分,它性能的高低直接关系到数据库性能的好坏。

我们知道,SQL语句同其它语言(如C语言)的语句不一样,它是非过程化(non-procedural)的语句,即当你要取数据时,不需要告诉数据库通过何种途径去取数据,如到底是通过索引取数据,还是应该将表中的每行数据都取出来,然后再通过一一比较的方式取数据(即全表扫描),这是由数据库的优化器决定的,这就是非过程化的含义,也就是说,如何取数据是由优化器决定,而不是应用开发者通过编程决定。在处理SQL的SELECT、UPDATE、INSERT或DELETE语句时,Oracle 必须访问语句所涉及的数据,Oracle的优化器部分用来决定访问数据的有效路径,使得语句执行所需的I/O和处理时间最小。

为了实现一个查询,内核必须为每个查询定制一个查询策略,或为取出符合条件的数据生成一个执行计划(execution plan)。典型的,对于同一个查询,可能有几个执行计划都符合要求,都能得到符合条件的数据。例如,参与连接的表可以有多种不同的连接方法,这取决于连接条件和优化器采用的连接方法。为了在多个执行计划中选择最优的执行计划,优化器必须使用一些实际的指标来衡量每个执行计划使用的资源(I/0次数、CPU等),这些资源也就是我们所说的代价(cost)。如果一个执行计划使用的资源多,我们就说使用执行计划的代价大。以执行计划的代价大小作为衡量标准,优化器选择代价最小的执行计划作为真正执行该查询的执行计划,并抛弃其它的执行计划。

在ORACLE的发展过程中,一共开发过2种类型的优化器:基于规则的优化器和基于代价的优化器。这2种优化器的不同之处关键在于:取得代价的方法与衡量代价的大小不同。现对每种优化器做一下简单的介绍:

基于规则的优化器 -- Rule Based (Heuristic) Optimization(简称RBO):
在ORACLE7之前,主要是使用基于规则的优化器。ORACLE在基于规则的优化器中采用启发式的方法(Heuristic Approach)或规则(Rules)来生成执行计划。例如,如果一个查询的where条件(where clause)包含一个谓词(predicate,其实就是一个判断条件,如”=”, “>”, ”<”等),而且该谓词上引用的列上有有效索引,那么优化器将使用索引访问这个表,而不考虑其它因素,如表中数据的多少、表中数据的易变性、索引的可选择性等。此时数据库中没有关于表与索引数据的统计性描述,如表中有多上行,每行的可选择性等。优化器也不考虑实例参数,如multi block i/o、可用排序内存的大小等,所以优化器有时就选择了次优化的计划作为真正的执行计划,导致系统性能不高。
如,对于

select * from emp where deptno = 10;

这个查询来说,如果是使用基于规则的优化器,而且deptno列上有有效的索引,则会通过deptno列上的索引来访问emp表。在绝大多数情况下,这是比较高效的,但是在一些特殊情况下,使用索引访问也有比较低效的时候,现举例说明:
1:emp表比较小,该表的数据只存放在几个数据块中。此时使用全表扫描比使用索引访问emp表反而要好。因为表比较小,极有可能数据全在内存中,所以此时做全表扫描是最快的。而如果使用索引扫描,需要先从索引中找到符合条件记录的rowid,然后再一一根据这些rowid从emp中将数据取出来,在这种条件下,效率就会比全表扫描的效率要差一些。

2:emp表比较大时,而且deptno = 10条件能查询出表中大部分的数据如(50%)。如该表共有4000万行数据,共放在有500000个数据块中,每个数据块为8k,则该表共有约4G,则这么多的数据不可能全放在内存中,绝大多数需要放在硬盘上。此时如果该查询通过索引查询,则是你梦魇的开始。db_file_multiblock_read_count参数的值200。如果采用全表扫描,则需要500000/db_file_multiblock_read_count=500000/200=2500次I/O。但是如果采用索引扫描,假设deptno列上的索引都已经cache到内存中,所以可以将访问索引的开销忽略不计。因为要读出4000万x 50% = 2000万数据,假设在读这2000万数据时,有99.9%的命中率,则还是需要20000次I/O,比上面的全表扫描需要的2500次多多了,所以在这种情况下,用索引扫描反而性能会差很多。在这样的情况下,用全表扫描的时间是固定的,但是用索引扫描的时间会随着选出数据的增多使查询时间相应的延长。
共3页: 上一页 1 [2] [3] 下一页
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: