二10、oracle经过复合索引优化查询及不走索引的8种状况

1. 理解ROWID
  ROWID是由Oracle自动加在表中每行最后的一列伪列,既然是伪列,就说明表中并不会物理存储ROWID的值;你能够像使用其它列同样使用它,只是不能对该列的值进行增、删、改操做;一旦一行数据插入后,则其对应的ROWID在该行的生命周期内是惟一的,即便发生行迁移,该行的ROWID值也不变。
SELECT t.rowid,t.* FROM DM_COMM_PREM_LIST t where LIST_ID= '3106355531';

2. SQL优化器优化方式
1)基于规则的优化器RBO(Rule-Based Optimization)
  RBO有严格的使用规则,只要按照这套规则去写SQL语句,不管数据表中的内容怎样,也不会影响到你的执行计划;换句话说,RBO对数据“不敏感”,它要求SQL编写人员必需要了解各项细则;RBO一直沿用至ORACLE 9i,从ORACLE 10g开始,RBO已经完全被抛弃。
2)基于成本的优化器CBO(Cost-Based Optimization)
       CBO是一种比RBO更加合理、可靠的优化器,在ORACLE 10g中彻底取代RBO;CBO经过计算各类可能的执行计划的“代价”,即COST,从中选用COST最低的执行方案做为实际运行方案;它依赖数据库对象的统计信息,统计信息的准确与否会影响CBO作出最优的选择,也就是对数据“敏感”。

3. 基于SQL优化器建立有效复合索引
3.1)INDEX SKIP SCAN(复合索引之索引跳跃扫描)
    Oracle 9i后提供,有时候复合索引的前导列(索引包含的第一列)没有在查询语句中出现,oralce也会使用该复合索引,
这时候就使用的INDEX SKIP SCAN;
3.2)何时会触发 INDEX SKIP SCAN
前提条件:表有一个复合索引,且在查询时有除了前导列(索引中第一列)外的其余列做为条件,而且优化器模式为CBO时当Oracle发现前导列的惟一值个数不多时,会将每一个惟一值都做为常规扫描的入口,在此基础上作一次查找,最后合并这些查询;
例如:
    假设表emp有ename(雇员名称)、job(职位名)、sex(性别)三个字段,而且创建了如 create index idx_emp on emp (sex, ename, job) 的复合索引;由于性别只有 '男' 和 '女' 两个值,因此为了提升索引的利用率,Oracle可将这个复合索引拆成 ('男', ename, job),('女', ename, job)这两个复合索引;当查询 select * from emp where job = 'Programmer' 时该查询发出后:    Oracle先进入sex为'男'的入口,这时候使用到了 ('男', ename, job) 这条复合索引,查找 job = 'Programmer' 的条目;再进入sex为'女'的入口,这时候使用到了 ('女', ename, job) 这条复合索引,查找 job = 'Programmer' 的条目;最后合并查询到的来自两个入口的结果集。

3.3)建立知足索引跳跃扫描条件的复合索引(含日期字段)后,可是查看执行计划却发现并未走复合索引
如:建立索引跳跃扫描 create index IDX_DM_FINISHTIME_ORGANID on DM_COMM_PREM_LIST (FINISH_TIME,ORGAN_ID) ;
查询执行计划以下图,发现未会走复合索引


如何解决此问题:修改日期设定的格式T1.FINISH_TIME >= TO_DATE('2017-06-01', 'yyyy-mm-ddhh24miss') AND       T1.FINISH_TIME <= TO_DATE('2017-06-23', 'yyyy-mm-ddhh24miss');经过将传入参数格式化成对应yyyy-mm-ddhh24miss格式字符串,这样由Oracle将字符串转成Date类型,就很顺利的走索引区间扫描。效果以下:html


参看博文:http://programdolt.iteye.com/blog/1186690

4.不走索引的缘由,大概有以下8种:
1)创建组合索引,但查询谓词并未使用组合索引的第一列,此处有一个INDEX SKIP SCAN概念。
2)在包含有null值的table列上创建索引,当时使用select count(*) from table时不会使用索引。
3)在索引列上使用函数时不会使用索引,若是必定要使用索引只能创建函数索引。
如:Where条件中对字段增长处理函数将不使用该列的索引
select * from emp where to_char(hire_date,'yyyymmdd')='20080411' (不使用)
select * from emp where hire_date = to_char('20080411','yyyymmdd') (使用)
4)当被索引的列进行隐式的类型转换时不会使用索引。数据库

示例1:oracle

select * from t where indexed_column = 5,而indexed_column列创建索引但类型是字符型,这时Oracle会产生隐式的类型转换,转换后的语句相似于select * from t where to_number(indexed_column) = 5,此时不走索引的状况相似于case3函数

示例2:日期转换也有相似问题
select * from t where trunc(date_col) = trunc(sysdate)其中date_col为索引列,这样写不会走索引,可改写成select * from t where date_col >= trunc(sysdate) and date_col < trunc(sysdate+1),此查询会走索引
5)并非全部状况使用索引都会加快查询速度,full scan table 有时会更快,尤为是当查询的数据量占整个表的比重较大时,由于full scan table采用的是多块读,
当Oracle优化器没有选择使用索引时不要当即强制使用,要充分证实使用索引确实查询更快时再使用强制索引。
6)<>
7)like’%dd’百分号在前
8)not in ,not exist优化

oracle中的索引扫描共计5种,本章只介绍INDEX SKIP SCAN(索引跳跃扫描),其余四种索引扫描会在另外章节总结
INDEX UNIQUE SCAN(索引惟一扫描)
INDEX RANGE SCAN(索引范围扫描)
INDEX FULL SCAN(索引全扫描)
INDEX FAST FULL SCAN(索引快速扫描)
参看博文:
https://www.cnblogs.com/sthinker/p/6080307.html
https://www.cnblogs.com/Dreamer-1/p/6076440.htmlspa

相关文章
相关标签/搜索