19cOCP 9月周末班 正在授课 欢迎试听         RHCE9 9月周末班 正在授课 欢迎试学         PGCE 认证专家,周末班报名中,欢迎垂询         数据库运维工程师招聘         RHCE认证培训钜惠学习         OCP认证培训组团活动特惠中!!!         MySQL认证周末班 正在招生 欢迎垂询!         

11种SQL中索引未使用的情况

更新时间: 2016-10-26 00:34

针对自己曾经经历过的一道面试题,那些情况不走索引,于是搜索网络和书籍的一些资料,整理如下:
 
1、查询谓词没有使用索引的主要边界,换句话说就是select *,可能会导致不走索引。
比如,你查询的是SELECT * FROM T WHERE Y=XXX;假如你的T表上有一个包含Y值的组合索引,但是优化器会认为需要一行行的扫描会更有效,这个时候,优化器可能会选择TABLE ACCESS FULL,但是如果换成了SELECT Y FROM T WHERE Y = XXX,优化器会直接去索引中找到Y的值,因为从B树中就可以找到相应的值。
 
2、单键值的b树索引列上存在null值,导致COUNT(*)不能走索引。
如果在B树索引中有一个空值,那么查询诸如SELECT COUNT(*) FROM T 的时候,因为HASHSET中不能存储空值的,所以优化器不会走索引,有两种方式可以让索引有效,一种是SELECT COUNT(*) FROM T WHERE XXX IS NOT NULL或者把这个列的属性改为not null (不能为空)。
 
3、索引列上有函数运算,导致不走索引
如果在T表上有一个索引Y,但是你的查询语句是这样子SELECT * FROM T WHERE FUN(Y) = XXX。这个时候索引也不会被用到,因为你要查询的列中所有的行都需要被计算一遍,因此,如果要让这种sql语句的效率提高的话,在这个表上建立一个基于函数的索引,比如CREATE INDEX IDX FUNT ON T(FUN(Y));这种方式,等于Oracle会建立一个存储所有函数计算结果的值,再进行查询的时候就不需要进行计算了,因为很多函数存在不同返回值,因此必须标明这个函数是有固定返回值的。
 
4、隐式转换导致不走索引。
索引不适用于隐式转换的情况,比如你的SELECT * FROM T WHERE Y = 5 在Y上面有一个索引,但是Y列是VARCHAR2的,那么Oracle会将上面的5进行一个隐式的转换,SELECT * FROM T WHERE TO_NUMBER(Y) = 5,这个时候也是有可能用不到索引的。
 
5、表的数据库小或者需要选择大部分数据,不走索引
在Oracle的初始化参数中,有一个参数是一次读取的数据块的数目,比如你的表只有几个数据块大小,而且可以被Oracle一次性抓取,那么就没有使用索引的必要了,因为抓取索引还需要去根据rowid从数据块中获取相应的元素值,因此在表特别小的情况下,索引没有用到是情理当中的事情。
 
6、cbo优化器下统计信息不准确,导致不走索引
很长时间没有做表分析,或者重新收集表状态信息了,在数据字典中,表的统计信息是不准确的,这个情况下,可能会使用错误的索引,这个效率可能也是比较低的。
 
7、!=或者<>(不等于),可能导致不走索引,也可能走 INDEX FAST FULL SCAN
例如select id  from test where id<>100
 
8、表字段的属性导致不走索引,字符型的索引列会导致优化器认为需要扫描索引大部分数据且聚簇因子很大,最终导致弃用索引扫描而改用全表扫描方式
由于字符型和数值型的在insert的时候排序不同,字符类型导致了聚簇因子很大,原因是插入顺序与排序顺序不同。详细点说,就是按照数字类型插入(1..3200000),按字符类型('1'...'32000000')t排序,在对字符类型使用大于运算符时,会导致优化器认为需要扫描索引大部分数据且聚簇因子很大,最终导致弃用索引扫描而改用全表扫描方式。
9.建立组合索引,但查询谓词并未使用组合索引的第一列,此处有一个INDEX SKIP SCAN概念,
 
10、like '%liu' 百分号在前请输入标题
 
11,not in ,not exist
可以尝试把not in 或者 not exsts改成左连接的方式(前提是有子查询,并且子查询有where条件)。
例如:
SELECT
    /*+ INDEX(I CIRCLEICONMAST_IX1)*/
    I.ICONNO,
    I.CIRCLEID,
    I.FILEPATH,
    I.REGDT,
    I.FILEPATH || '/' || I.FILENAME IMGNAME,
    I.FILEPATH || '/' || 'th_160_' || I.FILENAME SMALLIMGNAME,
    I.MEMBERID,
    I.ADMCHK STATUS,
    I.ADMCHK ORIGINALSTATUS,
    ROWNUM RN
     FROM CIRCLEICONMAST I
    WHERE I.REGDT BETWEEN TO_DATE('20120619', 'YYYYMMDD') - 10000 AND
      TO_DATE('20120621', 'YYYYMMDD')
      AND NOT EXISTS (
       SELECT C.VALIDFLG
         FROM CIRCLEMAST C
        WHERE C.VALIDFLG IN ('N', 'F')
        AND I.CIRCLEID = C.CIRCLEID)      
      AND I.ADMCHK = 'N'
 
改成左连接:
SELECT
/*+ INDEX(I CIRCLEICONMAST_IX1)*/
I.ICONNO,
I.CIRCLEID,
I.FILEPATH,
I.REGDT,
I.FILEPATH || '/' || I.FILENAME IMGNAME,
I.FILEPATH || '/' || 'th_160_' || I.FILENAME SMALLIMGNAME,
I.MEMBERID,
I.ADMCHK STATUS,
I.ADMCHK ORIGINALSTATUS,
ROWNUM RN
  FROM CIRCLEICONMAST I, CIRCLEMAST C
WHERE I.REGDT BETWEEN TO_DATE('20110620', 'YYYYMMDD') AND
       TO_DATE('20120621', 'YYYYMMDD') + 1
   AND C.VALIDFLG NOT IN ('N', 'F')
   AND I.CIRCLEID = C.CIRCLEID
      
   AND I.ADMCHK = 'N'
 
总结:oracle中有很多情况会导致index失效,并且走全表扫描的代价是相当大的,所以在写sql的时候一定要注意这个会使索引失效的情况,养成良好的习惯。

开班信息MORE>>

课程名称 开课时间 上课类型 状态
RHCE培训 11月 周末班 授课中...
OCP培训 10月 周末班 授课中...
PGCE 专家 11月 周末班 报名中...
OCP培训 12月 精英班 报名中...
OCM培训 11月 周末班 报名中...
RHCE培训 常年 周末班 报名中...
MySQL培训 常年 周末班 报名中...
<<