Oracle性能优化

ORACLE性能优化操作

1.避免对列的操作

任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。

比如:select * from record where  to_char(ActionTime,'yyyymmdd')='19991201'(10秒)

换成:select * from record where  ActionTime= to_date ('19991201' ,'yyyymmdd')(< 1秒)

2.避免不必要的类型转换

需要注意的是,尽量避免潜在的数据类型转换。

如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致全表扫描

比如:select col1,col2 from tab1 where col1>10;

换成:select col1,col2 from tab1 where col1>'10'; 

3.增加查询的范围限制

    增加查询的范围限制,避免全范围的搜索。

比如:select * from record where ActionTime < to_date ('20010301' ,'yyyymm');

换成:

  1. select * from record where ActionTime < to_date ('20010301' ,'yyyymm')  
  2. and ActionTime > to_date ('20010101' ,'yyyymm');  

4.尽量去掉"IN"、"OR
 含有"IN"、"OR"的Where子句常会使用工作表,使索引失效;

如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。  

比如:select count(*) from stuff where id_no in('0','1');
换成:select count(*) from stuff where id_no='0';select count(*) from stuff where id_no='1'

5.尽量去掉 "<>"
 尽量去掉 "<>",避免全表扫描

6.去掉Where子句中的IS NULL和IS NOT NULL
 Where子句中的IS NULL和IS NOT NULL将不会使用索引而是进行全表搜索。

7.索引提高数据分布不均匀时查询效率

索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。

A、数据分布不均匀的特殊情况下,选择性不高的索引也要创建。

表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取值范围为枚举值:[0,1,2,3,4,5,6,7]。

按照前面说的索引建立的规则,“选择性不高的字段不应该建立索引”,

该字段只有8种取值,索引值的重复率很高,索引选择性明显很低,因此不建索引。

然而,由于该字段上数据值的分布情况非常特殊,具体如下表:

取值范围                     占总数据量的百分比
1~5                                          1% 
6                                               98%
7                                               1%

而且,常用的查询中,查询DisposalCourseFlag<6 的情况既多又频繁,毫无疑问,如果能够建立索引,并且被用,

那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。

**复合索引:如果我们创建了(area,age,salary)的复合索引,那么其实相当于创建了(area,age,salary),(area,age),(area)三个索引,这样称为最佳左前缀特性

8. 利用HINT强制指定索引

在ORACLE优化器无法用上合理索引的情况下,利用HINT强制指定索引。

继续“oracle 性能优化操作七”的例子,ORACLE缺省认定,表中列的值是在所有数据行中均匀分布的,

也就是说,在一百万数据量下,每种DisposalCourseFlag值各有12.5万数据行与之对应。

假设SQL搜索条件DisposalCourseFlag=2,利用DisposalCourseFlag列上的索引进行数据搜索效率,

往往不比全表扫描的高,ORACLE因此对索引“视而不见”,从而在查询路径的选择中,用其他字段上的索引甚至全表扫描。

根据我们上面的分析,数据值的分布很特殊,严重的不均匀。为了利用索引提高效率,此时,

一方面可以单独对该字段或该表用analyze语句进行分析,对该列搜集足够的统计数据,使ORACLE在查询选择性较高的值时能用上索引;

另一方面,可以利用HINT提示,在SELECT关键字后面,加上“/*+ INDEX(表名称,索引名称)*/”的方式,强制ORACLE优化器用上该索引。

比如:select * from  serviceinfo where DisposalCourseFlag=1 ; 

换成:select /*+  INDEX(SERVICEINFO,IX_S_DISPOSALCOURSEFLAG)  */  *  from  serviceinfo 

    where DisposalCourseFlag=1;

如果查询语句中,表用到别名时,上边语句中的table一定要是别名,否则不走执行强制索引

9. 屏蔽无用索引

继续“oracle 性能优化操作八”的例子

由于实际查询中,还有涉及到DisposalCourseFlag=6的查询,而此时如果用上该字段上的索引,将是非常不明智的,效率也极低。

因此这种情况下,我们需要用特殊的方法屏蔽该索引,以便ORACLE选择其他字段上的索引。

比如,如果字段为数值型的就在表达式的字段名后,添加“+ 0”,为字符型的就并上空串:||""

比如:

  1. select * from  serviceinfo where DisposalCourseFlag+ 0 = 6 and workNo =  '36' ;  

10.分解复杂查询,用常量代替变量

        对于复杂的Where条件组合,Where中含有多个带索引的字段,考虑用IF语句分情况进行讨论;

同时,去掉不必要的外来参数条件,减低复杂度,以便在不同情况下用不同字段上的索引

11.like子句尽量前端匹配

  1. select * from city where name like ‘%S%’;  

以上查询的执行计划用了全表扫描(TABLE ACCESS FULL),如果能够修改为:

  1. select * from city where name like ‘S%’;  

那么查询的执行计划将会变成(INDEX RANGE SCAN),成功的利用了name字段的索引。

这意味着Oracle SQL优化器会识别出用于索引的like子句,只要该查询的匹配端是具体值。

因此我们在做like查询时,应该尽量使查询的匹配端是具体值,即使用like ‘S%’

12.用Case语句合并多重扫描

我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询:

[sql] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. select count(*) from emp where sal<1000;  
  2.   
  3. select count(*) from emp where sal between 1000 and 5000;  
  4.   
  5. select count(*) from emp where sal>5000;  

这样我们需要进行三次全表查询,但是如果我们使用case语句:

[sql] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. select   
  2.   
  3. count (sale when sal <1000  
  4.   
  5. then 1 else null end)              count_poor,  
  6.   
  7. count (sale when between 1000 and 5000  
  8.   
  9. then 1 else null end)              count_blue_collar,  
  10.   
  11. count (sale when sal >5000  
  12.   
  13. then 1 else null end)              count_poor  
  14.   
  15. from emp;  

这样查询的结果一样,但是执行计划只进行了一次全表查询。

13. 使用nls_date_format

例:

  1. select * from t_wip_tracking  where  to_char(in_station_time,'mm')='12';   

这个查询的执行计划将是全表查询,如果我们改变nls_date_format,

[sql] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. alter session set nls_date_format=’MM’;  

现在重新修改上面的查询:

[sql] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. select * from t_wip_tracking  where  in_station_time='12';  

这样就能使用in_station_time上的索引了,它的执行计划将是(INDEX RANGE SCAN)

14.使用基于函数的索引

前面谈到任何对列的操作都可能导致全表扫描,例如:

  1. select * from emp where substr(ename,1,2)=’SM’; 

但是这种查询又经常使用,我们可以创建一个带有substr函数的基于函数的索引,

  1. create index emp_ename_substr on eemp ( substr(ename,1,2) );

这样在执行上面的查询语句时,这个基于函数的索引将排上用场,执行计划将是(INDEX RANGE SCAN)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值