首页 > 数据库 > Oracle > 2011-03-14 Oracle优化方式和模式
Oracle优化器的优化方式和优化模式
Oracle在执行一个SQL之前,首先要分析一下语句的执行计划,然后再按
执行计划去执行。分析语句的执行计划的工作是由优化器(Optimizer)
来完成的。不同的情况,一条SQL可能有多种执行计划,但在某一时点,
一定只有一种执行计划是最优的,花费时间是最少的
1、优化器的优化方式
如何设置基于规则和成本的优化方式
第一:CHOOSE
第三:FIRST_ROWS_n
第五:RULE
如何更改 optimizer_mode 的参数呢?可以用以下的方法。SQL> alter session set optimizer_mode='RULE';
********************************************************************************************
EXISTS语法
EXISTS
语法:
参数:
结果类型
结果值:
select
使用EXISTS去掉重复值
--用exists去掉重复行
通过使用EXISTS,Oracle会首先检查主查询,然后运行子查询直到
它找到第一个匹配项,这就节省了时间。Oracle在执行IN子查询时,
首先执行子查询,并将获得的结果列表存放在一个加了索引的临时表
中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,
存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN
通常查询速度快的原因。
附录:UNION用法
为了合并多个select语句的查询结果,可以使用集合操作符UNION,UNION ALL
语法如下:
.
.
访问Table的方式
ORACLE
采用两种访问表中记录的方式:
a.
全表扫描就是顺序地访问表中每条记录.
ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描.
b.
清空共享池的语法:
alter system flush buffer_cache
1.
设置基于规则的优化器
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表
driving
table)将被最先处理.
在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时,
会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并
例如:
表 TAB1 16,384
条记录
表
TAB2 1
条记录
选择TAB2作为基础表
(最好的方法)
选择TAB1作为基础表
(不佳的方法)
2
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,
那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.
效率低
3
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用
‘*'
是一个方便的方法.不幸的是,这是一个非常低效的方法.
4.
计算记录条数
和一般的观点相反,
count(*)
比count(1)稍快
,
当然如果可以通过索引检索,对索引列的计数仍旧是最快的.
例如 COUNT(EMPNO)
(在论坛中曾经对此有过相当热烈的讨论,
这个观点并不十分准确,通过实际的测试,上述三种方法并没有显著的性能差别)
设置基于规则的优化器
select count(empno) from
ids_emp
5.
用Where子句替换HAVING子句
避免使用HAVING子句, HAVING
只会在检索出所有记录之后才对结果集进行过滤.
这个处理需要排序,总计等操作.
如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.
例如
低效:
(HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中)
6.
使用表的别名(Alias)
当在SQL语句中连接多个表时,
请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
(Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的
归属)
7.
用EXISTS替代IN
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下,
使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
设置基于基于成本的优化器
下面连接语句设置基于成本的优化器执行快
alter system set optimizer_mode=ALL_ROWS
设置基于规则的优化器
alter system set optimizer_mode=RULE
效率低(增加索引)
select * from ids_emp
where deptno
效率高(增加索引)
select * from ids_emp e
where exists(select *
from ids_dept d where
and
8.
用NOT
EXISTS替代NOT IN
在子查询中,NOT IN子句将执行一个内部的排序和合并.
无论在哪种情况下,NOT
IN都是最低效的
(因为它对子查询中的表执行了一个全表遍历).
为了避免使用NOT IN
,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
效率低(增加索引)
select * from ids_emp
where deptno not in(select deptno from ids_dept where loc='a')
效率高(增加索引)
select * from ids_emp e
where
and
9.
用表连接替换EXISTS
通常来说 ,
采用表连接的方式比EXISTS更有效率
and
10..
用EXISTS替换DISTINCT
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用
DISTINCT.
一般可以考虑用EXIST替换
select distinct
d.deptno,d.dname
where e.deptno=d.deptno
select d.deptno,d.dname
where exists( select * from ids_emp e
where e.deptno=d.deptno)
11
下面是检索月薪大于2000的表达式:
sal
sal
sal*12
如果SQL语句包括第一种情况,优化器会简单地把它转变成第二种。
优化器不会简化跨越比较符的表达式,例如第三条语句,鉴于此,应尽量写用常量跟字段比较检索的表达式,而不要将字段置于表达式当中。否则没有办法优化,比如如果sal上有索引,第一和第二就可以使用(执行索引),第三就难以使用(sal*12 不识别索引)。
12
如果不产生大量重复值,可以考虑把子句拆开。拆开的子句中应该包含索引。
13
在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询 10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学生表(学号、姓名、年龄??)和选课表(学号、课程号、成绩)。如果两个表要做连接,就要在“学号”这个连接字段上建立索引。
还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的WHERE子句强迫优化器使用顺序存取。
使用设置基于基于成本的优化器来测试
下面的查询将强迫对ide_emp表执行顺序操作:
select * from ids_emp
时间 17秒左右
虽然在empno上建有索引,但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合,所以应该改为如下语句:
SELECT * FROM ids_emp WHERE deptno=10
and deptno=20
UNION
SELECT * FROM ids_emp WHERE empno=3000
这样就能利用索引路径处理查询。
时间 0.078秒左右
注:UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
14
一个列的标签同时在主查询和WHERE子句中的查询中出现,那么很可能当主查询中的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/23953801/viewspace-1115862/ ,如需转载,请注明出处,否则将追究法律责任。