Oracle建立索引的目的是为了避免全表扫描,提高查询的效率。

但是有些情况下,即使建立了索引,但是执行写出来的查询还是很慢,然后通过执行计划会发现是索引失效导致的(不走索引,走全表扫描)。所以需要了解一下有哪些些情况会导致索引失效,即查询不走索引的原因。

在写SQL的层面上一些骚操作会导致索引失效

  • 没有写WHERE子句或查询条件没有建立索引

既然没有WHERE子句,那么就是查询全部数据了,相当于全表扫描,当然不走索引了。

而查询条件上没有建立索引的话,索引都没有还走个毛索引啊。

  • WHERE子句上没有使用索引中的引导列

要使用索引,则查询条件中必须包含索引中的引导列。比如一个复合索引包含A,B,C,D四列,则A为引导列(排在第一位置的列)。如果WHERE子句中所包含的列是BCD或者BD等情况,则只能使用非匹配索引扫描。

-- 创建包含A,B,C,D四列的复合索引
CREATE INDEX INDEX_ABCD ON LETTERS(A, B, C, D);
-- 下列语句不会使用复合索引
SELECT * FROM LETTERS WHERE B = 'b' AND C = 'c';
SELECT * FROM LETTERS WHERE B = 'b' AND D = 'd';
SELECT * FROM LETTERS WHERE C = 'c' AND D = 'd';
SELECT * FROM LETTERS WHERE B = 'b' AND C = 'c' AND D = 'd';

另外,单独引用复合索引里排第一位置的索引列也会导致索引失效,复合索引必须复合使用才能生效。

-- 单独使用复合索引中的引导列也不会触发复合索引
SELECT * FROM LETTERS WHERE A = 'a'
  • WHERE子句中使用IS NULL或IS NOT NULL

使用判断空或非空的条件会导致该索引列失效。

-- COMM列的索引会失效
SELECT * FROM EMP WHERE COMM IS NULL;
  • WHERE子句中使用函数

如果没有使用基于函数的索引,那么WHERE子句中对存在索引的列使用函数时,会使优化器忽略这些索引。

-- 在没有建立基于函数索引的字段上使用了函数,会导致索引失效
SELECT * FROM STUFF WHERE TRUNC(BIRTHDAY) = '2019-04-01'

非要这样的话可以通过在索引列上建立基于函数的索引来解决问题。

-- 给BIRTHDAY列创建TRUNC函数的函数索引
CREATE INDEX STUFF_BIRTHDAY_FBI_IDX ON STUFF(TRUNC(BIRTHDAY));

这样的话函数索引就起作用了,也就能在索引列上使用函数了,而且这时候你想不用函数都不行。

但是对于MIN,MAX函数等,Oracle仍然会使用索引,因为Oracle对这类聚合分析函数做了相应的优化。

  • 对索引列进行运算导致索引失效

和使用函数同样的,如果使用运算,比如加减乘除非等,也会导致索引失效。

-- 对索引列进行了减法运算,导致不走索引
SELECT * FROM USERS WHERE AGE - 1 = 23-- 正确的写法(去除运算)
SELECT * FROM USERS WHERE AGE = 24
  • 使用前导模糊查询

前导模糊查询的写法是LIKE ‘%T’,即通配符【%】写在要匹配的字符前面,这样的情况下不走索引。

-- 前导模糊查询不走索引
SELECT * FROM LOVERS WHERE NAME LIKE '%静';
  • WHERE子句中使用不等于条件

不等于操作包括:

<>
!=
NOT COL >= ?
NOT COL <= ?

为什么不等于条件会不走索引,我们可以用常规的思维去推断一下。首先【不等于】这个概念可以推断成选取结果集中的一个比较大的部分,比如我们要找出中国人口中不是姓杨的,要找出资深程序员中不会秃头的,都可以认为是要返回结果集中一个很大的部分。因为Oracle的CBO是闭源的,我们只能推断Oracle会认为既然要返回结果集中很大的一个部分,不如直接使用全表扫描而不考虑索引。

而且Oracle是建议,对于这些限制条件可以使用OR代替,例如COL <> 0可以替换成COL > 0 OR COL < 0。

  • WHERE子句中使用NOT IN或NOT EXISTS

使用NOT IN或NOT EXISTS也会导致不走索引。

事实上NOT IN和NOT EXISTS也可以看做是不等于条件,不走索引的原因和上面的不等于条件相同。

另外有一些人说使用IN是不走索引的,这是不对的,IN是可以走索引的,只是可能效率会比EXISTS低。

  • 等于和范围索引不会被合并使用
SELECT * FROM CARS WHERE COLOR = 'yellow' AND TYPE = 'B'

在上面的查询中,COLOR和TYPE列上都创建了非唯一索引,在这种查询条件下Oracle并不会合并索引,而只会使用第一个索引,即只有COLOR列上索引会生效。

  • 比较不匹配类型的数据类型

比如SERIAL_CODE是一个VARCHAR2类型的字段,在这个字段上建立了索引,但是下面的语句将会执行全表扫描而不走索引。

SELECT * FROM MATERIALS WHERE SERIAL_CODE = 810646874;

为什么呢?因为Oracle中有一个字段自动进行隐式类型转换的机制,会自动把类型不匹配的字段进行隐式类型转换,相当于:

SELECT * FROM MATERIALS WHERE TO_NUMBER(SERIAL_CODE) = 810646874;

可以看出,Oracle优化器自动给SERIAL_CODE加上了类型转换函数,这样就限制了索引的使用。

所以正确的写法应该是条件和字段类型相匹配:

SELECT * FROM MATERIALS WHERE SERIAL_CODE = '810646874';

表中数据量的多少也会影响索引的使用

  • 查询的数量是大表的大部分,应该是30%以上

如果查询的数量超过大表数量的30%,那就不走索引了。

  • 对小表查询

举个极端的例子,表中只有一条数据,何必走索引呢。比如你看一本只有几页的书,难道你还会去看目录吗,给这本书建目录都是人才了,你还去找这本书有没有目录岂不是人才中的人才(你别去上班了,我建目录养你啊)。

索引失效的解决办法

下面这些解决办法是基于SQL写得没问题,而索引就是不生效的情况。

  • 选用合适的Oracle优化器

Oracle的优化器有三种,一种是基于规则的(RULE),一种是基于成本的(COST),还有一种是选择性的(CHOOSE)。

在缺省的情况下(未设置),Oracle默认采用CHOOSE优化器。为了避免那些不必要的全表扫描(FULL TABLE SCAN),你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或基于成本的优化器。

  • 重建索引

和电脑出了问题的重启试试一样,索引出了问题也是可以重建试试的。

ALTER INDEX 索引名 REBUILD
  • 强制索引

强制索引是使用hint关键字。

正常使用的索引突然失效的对应解决办法

有些时候,同样的SQL,之前是能走索引的,突然有一天不走索引了,那么可能是:

1.随着表的增长,WHERE条件出来的数据太多,大于15%,导致CBO计算出走索引扫描大于走全表扫描,就会使得索引失效。这种情况目前我也不知道该怎么办(好难啊)。

2.统计信息失效。这种情况需要重新搜集统计信息。

3.索引本身失效。这种情况就很玄乎了,只能重建索引试试。

转载自:oracle查询不走索引的一些情况(索引失效)

oracle查询不走索引的一些情况(索引失效)相关推荐

  1. oracle查询性能表关联,通过调节索引 优化Oracle关联查询性能

    本文引用一套实验室信息管理系统(LIS)使用的数据库,假设我们要查询2008年11月做检验的患者记录,条件是大于80岁,姓周的患者,最终结果按检查日期进行倒序排列.要使用的表有三个: ◆lis_rep ...

  2. oracle查询不走索引全表扫描,使用索引快速全扫描(Index FFS)避免全表扫描的若干场景-Oracle...

    使用索引快速全扫描(Index FFS)避免全表扫描的若干场景 什么使用使用Index FFS比FTS好? Oracle 8的Concept手册中介绍: 1. 索引必须包含所有查询中参考到的列. 2. ...

  3. oracle查询sql走索引吗,Oracle SQL不走索引小记

    sql执行计划不走索引 一.优化器认为走全表扫描更优. 在这种情况下,需要重新分析一遍表,更新表的状态,有助于优化器分析出正确的执行计划. analyze table tablename comput ...

  4. oracle怎样查询能利用索引,oracle怎样查询索引的使用情况

    查询用户的索引 select index_name,table_name,tablespace_name, index_type,uniqueness ,status from dba_indexes ...

  5. 作为唯一索引_Mysql什么情况下不走索引?

    本文基于Mysql5.7版本和InnoDB存储引擎. 1.InnoDB索引组织表 在InnoDB引擎中,表都是按照主键顺序组织存放的,这种存放方式的表称为索引组织表.InnoDB存储引擎中的表,都有主 ...

  6. oracle查询两列合并成一列_MySQL复合索引和单列索引的单表查询分析

    本文由读者小平同志投稿,小平是一位非常朴实认真的猿,现于某上市证券公司做微服务开发,对 MySQL 优化有深入研究,小平的博客地址是https://blog.csdn.net/weixin_41193 ...

  7. 生产问题分析!delete in子查询不走索引?!

    前言 文章开篇前,先问大家一个问题:delete in子查询,是否会走索引呢?很多伙伴第一感觉就是:会走索引.最近我们有个生产问题,就跟它有关.本文将跟大家一起探讨这个问题,并附上优化方案. 问题复现 ...

  8. oracle重建索引对空间的使用,分析oracle索引空间使用情况,以及索引是否需要重建...

    分析索引空间使用情况,以及索引是否需要重建 分析其他用户下的索引需要 analyze any的权限 分析索引前先查看表的大小和索引的大小,如果索引大小和表大小一样大或者大于表的大小,那么可以判断索引可 ...

  9. oracle 查询索引个数,Oracle数据库索引的创建和查询

    索引命名规范:普通索引最好i_开头,唯一索引最好u_开头,primary key索引最好pk_开头 1.创建索引:create index 索引名 on 表名(字段名); 2.查询索引 oracle中 ...

最新文章

  1. 三个点在同一个半圆的概率_【国际数学竞赛】列方程求概率
  2. IDisposable 接口介绍
  3. echarts图表第一个案例
  4. web工程中集成cas单点登录
  5. 编译linux内核成vmlinuz,编译一个内核 - no bzImage/vmlinuz生成
  6. Content Aware ABR技术
  7. 部署Small Business Server 2003服务器之一
  8. bat与C语言混合编程,BAT与HTML混合编程的方法
  9. 167. Two Sum II - Input array is sorted (C, C++, Python)
  10. 题目552-小数阶乘-nyoj20140811
  11. java 链表_java数据结构与算法之顺序表与链表深入分析(一)
  12. Base64 的 JavaScript 实现 js-base64
  13. 用Java实现一个学生管理系统(附源码)
  14. java int 转换成byte_Java如何将int转换为byte?
  15. 【006】- Django模型数据操作(二)
  16. JAVA 16方格排序游戏
  17. 关于VB.net禁用右键菜单的实现
  18. AcWing 188. 武士风度的牛
  19. SSM框架 基于Bootstrap fileinput 实现文件上传功能
  20. 磁盘分析管理软件:Disk Space Analyzer Pro mac版

热门文章

  1. Android的apk安装时签名相同冲突解决
  2. 「翻译」Vue3 相比 Vue2 都有哪些优化?
  3. 安恒2018.10 level1思路讲解
  4. Java实战之管家婆记账系统(8)——添加账目界面及功能实现
  5. Unpacking objects
  6. Handler基本使用(一) new Handler
  7. rust提示游戏安全违规_RUST 游戏启动不了 每次都是 Rust Launcher Error: Loading Error - Start Service failed (1450)...
  8. Linux学习笔记RHEL 7(一)--RedHatEnterpriseLinux 7.0安装过程
  9. 字符串流stringstream(头文件sstream)
  10. c++实现种子填充算法与扫描线算法