首先我们要知道的一点就是CBO的代码oracle是不会对我们公开的,起码现在是。所以本文中的结论不一定适用所有的版本。在应用本文的结论之前最好先试一下。

ok 下面就是本文的结论,当你在where语句中使用不等于或者not in时候,oracle 倾向于忽略索引。 比如:

SQL> Select * from test where text<>'star';

        ID TEXT
---------- ------------
4939426 sun

这条语句即使在test上有索引,oracle也仍然会忽略。

接下来我们分析证明一下这是为什么。 其实,我认为oracle这么做是有道理的。一般我们在写SQL的时候,如果用了 <>,也就是不等于,通常都是说选取结果集中的很大一部分。我们可以感受一下平时我们的思维方式和和习惯确实是这样的。比如我们说要"找出这些人中不是姓李的","找出这些车中不是大众的"。这一般来说是要返回结果集中很大一部分的。Oracle认为如果是这样,那么用索引不如全表扫描迅速,所以这种情况根本就不考虑索引,直接采用全表扫描。 而且oracle认为,如果你知道你的<>会返回少量的结果,那么你应该会调整你的SQL 用 (< or >)来代替。

下面我们验证一下。

首先创建表。一个很大的表。

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE 10.2.0.5.0 Production
TNS for Solaris: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production SQL> create table test as select rownum id, 'star' text from dba_objects,v$session; Table created.

验证一下这个表是不是很大,然后插入一条数据。

SQL> select count(*) from test;

  COUNT(*)
----------
4939425 SQL> insert into test values (4939426,'sun'); 1 row created. SQL> commit; Commit complete.

创建索引,并收集统计信息。

SQL> create index test_i on test(text);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname=> 'SYS', tabname=> 'TEST' ,cascade=> true);

PL/SQL procedure successfully completed.

进行10053trace

SQL> alter session set tracefile_identifier='haha';

Session altered.

SQL> ALTER SESSION SET EVENTS='10053 trace name context forever, level 1';

Session altered.

SQL> Select * from test where text<>'star';

        ID TEXT
---------- ------------
4939426 sun SQL> ALTER SESSION SET EVENTS '10053 trace name context off'; Session altered.

现在我们看一下10053的结果。

***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
Table: TEST Alias: TEST
#Rows: 4944655 #Blks: 10780 AvgRowLen: 10.00
Index Stats::
Index: TEST_I Col#: 2
LVLS: 2 #LB: 10468 #DK: 1 LB/K: 10468.00 DB/K: 19790.00 CLUF: 19790.00
***************************************
SINGLE TABLE ACCESS PATH
-----------------------------------------
BEGIN Single Table Cardinality Estimation
-----------------------------------------
Column (#2): TEXT(CHARACTER)
AvgLen: 5.00 NDV: 1 Nulls: 0 Density: 1
Table: TEST Alias: TEST
Card: Original: 4944655 Rounded: 1 Computed: 1.00 Non Adjusted: 1.00
-----------------------------------------
END Single Table Cardinality Estimation
-----------------------------------------
Access Path: TableScan
Cost: 3098.02 Resp: 3098.02 Degree: 0
Cost_io: 2360.00 Cost_cpu: 2153524223
Resp_io: 2360.00 Resp_cpu: 2153524223
Best:: AccessPath: TableScan
Cost: 3098.02 Degree: 1 Resp: 3098.02 Card: 1.00 Bytes: 0
***************************************
OPTIMIZER STATISTICS AND COMPUTATIONS
***************************************
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
Permutations for Starting Table :0
***********************
Join order[]: TEST[TEST]#0
***********************
Best so far: Table#: 0 cost: 3098.0217 card: 1.0000 bytes: 10
(newjo-stop-1) k:0, spcnt:0, perm:1, maxperm:80000
*********************************
Number of join permutations tried: 1
*********************************
Final - All Rows Plan: Best join order: 1
Cost: 3098.0217 Degree: 1 Card: 1.0000 Bytes: 10
Resc: 3098.0217 Resc_io: 2360.0000 Resc_cpu: 2153524223
Resp: 3098.0217 Resp_io: 2360.0000 Resc_cpu: 2153524223
kkoipt: Query block SEL$1 (#0)
******* UNPARSED QUERY IS *******
SELECT "TEST"."ID" "ID","TEST"."TEXT" "TEXT" FROM "SYS"."TEST" "TEST" WHERE "TEST"."TEXT"<>'star'
kkoqbc-subheap (delete addr=ffffffff7b11c008, in-use=11712, alloc=26392)
kkoqbc-end
: call(in-use=15256, alloc=49184), compile(in-use=37792, alloc=40520)
apadrv-end: call(in-use=15256, alloc=49184), compile(in-use=38608, alloc=40520) sql_id=192f8vs3fqvpc.
Current SQL statement for this session:
Select * from test where text<>'star' ============
Plan Table
============
-------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 3098 | |
| 1 | TABLE ACCESS FULL | TEST | 1 | 10 | 3098 | 00:00:38 |
-------------------------------------+-----------------------------------+
Predicate Information:
----------------------
1 - filter("TEXT"<>'star')

注意access pass 这里

  Access Path: TableScan
Cost: 3098.02 Resp: 3098.02 Degree: 0
Cost_io: 2360.00 Cost_cpu: 2153524223
Resp_io: 2360.00 Resp_cpu: 2153524223
Best:: AccessPath: TableScan
Cost: 3098.02 Degree: 1 Resp: 3098.02 Card: 1.00 Bytes: 0

根本就没有去calculate index的开销。 所以执行计划就是全表扫描。

之前也怀疑过<>这种方式会不走索引,但是不知道为什么没有当回事,这次一定要记住 非常有用。

not in 和 <> 不走索引的更多相关文章

  1. 诊断一句SQL不走索引的原因

    from http://www.itpub.net/thread-1852897-1-1.html 有论坛朋友在上面的帖子里问SQL为什么不走索引,正好这两天我也刚刚在看SQL优化,于是试着回答了一下 ...

  2. Select * 一定不走索引是否正确?

    Select * 一定不走索引是否正确? 走索引指的是:SQL语句的执行计划用到了1.聚集索引查找  2.索引查找  ,并且查询语句中需要有where子句 根据where子句的过滤条件,去聚集索引或非 ...

  3. Update关联查询不走索引,效率低下

    优化一个sql,就是有A,B两个表,要利用b表的字段更新a表对应的字段.形如 Sql代码 update A set A.a=(select B.b from B where A.id=B.id); 原 ...

  4. 【摘】Oracle执行计划不走索引的原因总结

    感谢原博主 http://soft.chinabyte.com/database/364/12471864.shtml 在Oracle数据库操作中,为什么有时一个表的某个字段明明有索引,当观察一些语的 ...

  5. oracle查询不走索引的一些情况(索引失效)

    Oracle建立索引的目的是为了避免全表扫描,提高查询的效率. 但是有些情况下发现即使建立了索引,但是写出来的查询还是很慢,然后会发现是索引失效导致的,所以需要了解一下那些情况会导致索引失效,即查询不 ...

  6. MySql Delete不走索引问题

    如果delete语句带有查询,写法不对会导致不走索引. 简单粗暴的办法:拆两条sql,一条查询,一条delete ======================= [不走索引的写法] DELETE FR ...

  7. mysql 索引 大于等于 走不走索引 最左前缀

    你可以认为联合索引是闯关游戏的设计 例如你这个联合索引是state/city/zipCode 那么state就是第一关 city是第二关, zipCode就是第三关 你必须匹配了第一关,才能匹配第二关 ...

  8. oracle order by 字段不能为空 为空速度慢 不走索引

    oracle order by 字段不能为空 为空速度慢 不走索引

  9. mysql 索引优化,索引建立原则和不走索引的原因

    第一:选择唯一性索引 唯一性索引的值是唯一的,可以更快捷的通过该索引来确定某条记录. 2.索引的列为where 后面经常作为条件的字段建立索引 如果某个字段经常作为查询条件,而且又有较少的重复列或者是 ...

  10. oracle 不走索引的原因

    create table tb2 as select * from emp;alter table tb2 modify empno number(4) not null;翻到20W行 create ...

随机推荐

  1. ckeditor详细设置

    CKEditor 3 JavaScript API Documentation : http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.con ...

  2. codevs3002石子归并3(四边形不等式优化dp)

    3002 石子归并 3 参考 http://it.dgzx.net/drkt/oszt/zltk/yxlw/dongtai3.htm  时间限制: 1 s  空间限制: 256000 KB  题目等级 ...

  3. 在JavaScript中"+"什么时候是链接符号,什么时候是加法运算?

    二元加法运算符“+”在两个操作数都是数字或都是字符串时,计算结果是显而易见的.加号“+”的转换规则优先考虑字符串连接,如果其中一个操作数是字符串或者转换为字符串的对象,另外一个操作数会转换为字符串,加 ...

  4. phpStorm更新后配置svn无法使用

    phpStorm迎来新的更新,结果之前配置的svn竟然无法使用啦,快捷键一类也没有作用.各种查找解决方案,最后找到解决方案.点击File找到Settings,找到Plugins这个部分,这个部分是管理 ...

  5. 第10篇 WINDOWS2003服务器 IIS上配置404页面的图文教程

    打开IIS 找到你的网站,点右键,选择属性 选择“自定义错误”标签页,找到404的那一项,点“编辑属性”按钮 (方案一)在“消息类型”里选“URL”,然后在下面的“URL”输入框里,填上你的404错误 ...

  6. Spring思维课程导图——bean属性的设置

  7. C# 文件操作【转】

    本文也收集了目前最为常用的C#经典操作文件的方法,具体内容如下:C#追加.拷贝.删除.移动文件.创建目录.递归删除文件夹及文件.指定文件夹下面的所有内容copy到目标文件夹下面.指定文件夹下面的所有内 ...

  8. SAS进阶《深入解析SAS》之对多数据集的处理

    SAS进阶<深入解析SAS>之对多数据集的处理 1. 数据集的纵向串接: 数据集的纵向串接指的是,将两个或者多个数据集首尾相连,形成一个新的数据集. 据集的横向合并: 数据集的横向合并,指 ...

  9. Android 升级安装APK兼容Android7.0,解决FileUriExposedException

    我们在开发app时避免不了需要添加应用内升级功能.当app启动时,如果检测到最新版本,将apk安装包从服务器下载下来,执行安装.安装apk的代码一般写法如下,网上随处可以搜到 public stati ...

  10. wampserver修改mysql数据库密码的简单方式

    刚装好的wampserver的数据库是没有密码的,所以可以直接登录,要设置密码,一种简单的方式如下: 打开phpMyadmin 初始状态没有密码,可以直接登录 登录之后,点击账户 点击修改权限,设置你 ...