oracle查询不走索引的一些情况(索引失效)
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 = '';
表中数据量的多少也会影响索引的使用
查询的数量是大表的大部分,应该是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 查询各表空间使用情况--完善篇
Oracle 查询各表空间使用情况--完善篇 链接:http://blog.itpub.net/28602568/viewspace-1770577/ 标题: Oracle 查询各表空间使用情况--完 ...
- ORACLE 查询不走索引的原因分析,解决办法通过强制索引或动态执行SQL语句提高查询速度
(一)索引失效的原因分析: <>或者单独的>,<,(有时会用到,有时不会) 有时间范围查询:oracle 时间条件值范围越大就不走索引 like "%_" ...
- ORACLE查询数据库的锁表情况
查询数据库的锁表情况语句如下: SELECT p.spid,a.serial#, c.object_name,b.session_id,b.oracle_username,b.os_user_na ...
- oracle怎样查询索引的使用情况
查询用户的索引select index_name,table_name,tablespace_name, index_type,uniqueness , status from dba_indexes ...
- oracle查询中会使索引无效的情况总结
总结一下oracle中会使索引无效的情况 1 无where条件: 2 索引列进行运算时: 3 使用like,并且通配符在前的情况: 4 字符型字段为数字时在where条件里不添加引号: 5 not i ...
- oracle查询所有用户表的表名、主键名称、索引、外键等
1.查找表的所有索引(包括索引名,类型,构成列): select t.*,i.index_type from user_ind_columns t,user_indexes i where t.ind ...
- Update关联查询不走索引,效率低下
优化一个sql,就是有A,B两个表,要利用b表的字段更新a表对应的字段.形如 Sql代码 update A set A.a=(select B.b from B where A.id=B.id); 原 ...
- oracle 查询索引和主键
ORACLE: 1.查主键名称: select * from user_constraints where table_name = 'AAA' and constraint_type ='P'; 查 ...
- 分析oracle索引空间使用情况,以及索引是否须要重建
分析索引空间使用情况.以及索引是否须要重建 分析其它用户下的索引须要 analyze any的权限 分析索引前先查看表的大小和索引的大小,假设索引大小和表大小一样大或者大于表的大小,那么能够推断索引可 ...
随机推荐
- java实现支付宝支付及退款(二)
紧跟上篇博客,本篇将书写具体的代码实现 开发环境:SSM.maven.JDK8.0 1.Maven坐标 <!--阿里支付--> <dependency> <groupId ...
- 【BZOJ3451】Normal
[BZOJ3451]Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治! 这个算法的核心是这样的: 消耗时间=0 Solve(树 a) 消耗时间 += a 的 大 ...
- 5255 -- 【FJOI2016】神秘数
5255 -- [FJOI2016]神秘数 Description 一个可重复数字集合\(S\) 的神秘数定义为最小的不能被 \(S\) 的子集的和表示的正整数.例如: \(S = {1,1,1,4, ...
- Spark大数据平台安装教程
一.Spark介绍 Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎.Spark是开源的类Hadoop MapReduce的通用并行框架,Spark拥有Hadoop MapRe ...
- Python入门学习:1.变量和简单的数据类型
python入门学习:1.变量和简单的数据类型 关键点:变量.字符串.数字 1.1 变量的命名和使用1.2 字符串1.3 数字1.4 注释 1.1 变量的命名和使用 变量,顾名思义是一个可变的量, ...
- .Net使用Redis详解之ServiceStack.Redis(七) 转载https://www.cnblogs.com/knowledgesea/p/5032101.html
.Net使用Redis详解之ServiceStack.Redis(七) 序言 本篇从.Net如何接入Reis开始,直至.Net对Redis的各种操作,为了方便学习与做为文档的查看,我做一遍注释展现 ...
- tomcat 改端口 运维最最重要的就是有看日志的习惯
tomcat一台机器上多实例更改端口需要改三个端口 改tomcat关闭端口 <Server port="9006" shutdown="SHUTDOWN" ...
- Vim 去除因为 Unix 和 Windows 换行符不同带来的 ^M 问题
由于各操作系统对换行符的处理不同, Unix: \n Windows : \r\n Mac : \r 所以有时 Vim 打开的文件会有如下情况: 解决方法为:在 Vim 中执行命令 :%s/\r//g ...
- Android/Linux boot time分析优化
如果需要优化boot time,就需要一个量化的工具来分析每个阶段的时间消耗.这种类型的优化特别适合使用基于timeline的图表,有着明显的时间顺序.要求不但能给出整个流程消耗的时间,还要能对流程进 ...
- Charles抓包显示乱码解决方法
[问题现象] 在抓https协议请求时,Request和Response显示乱码了: [解决办法] 第一步:点击 [工具栏-->Proxy-->SSL Proxying Settings. ...