`
kavy
  • 浏览: 888276 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

索引失效系列——说说is null

 
阅读更多

索引是我们进行优化的一种重要方式。实际工作中,一个简单的索引,可能就会大大提升提高关键业务作业效率,最终提升用户满意度。在CBO时代,DBA和开发人员经常为索引为什么不出现在执行计划中而困惑。

 

 

问题提出

 

我们在一些SQL优化的规则中(虽然已经进入了CBO时代),经常看到“where条件中出现is null,搜索不走索引”这样的说法。这样说法的原因是什么呢?我们通过实验一起来看一下。

 

 

SQL> create table t as select * from dba_objects;

 

Table created

 

SQL> update t set wner=null where wner='SCOTT';

 

34 rows updated

 

SQL> commit;

 

Commit complete

 

 

数据总量为:

 

 

SQL> select count(*) from t;

 

 COUNT(*)

----------

    51367

 

 

针对owner列为空的情况来说,超过五万的数据列中只有34行,选择性是相当好的,起码对于null来说。那么,我们加入索引。

 

SQL> create index idx_t_owner on t(owner);

 

Index created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

 

PL/SQL procedure successfully completed

 

 

下面我们实验对is null条件的检索路径。

 

 

SQL> explain plan for select * from t where owner is null;

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id | Operation        | Name | Rows | Bytes | Cost (%CPU)| Time    |

--------------------------------------------------------------------------

|  0 | SELECT STATEMENT |     |   70 | 6510 |  158  (2)| 00:00:02 |

|* 1 | TABLE ACCESS FULL| T   |   70 | 6510 |  158  (2)| 00:00:02 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

  1 - filter("OWNER" IS NULL)

 

13 rows selected

 

SQL> rollback;

 

Rollback complete

 

 

现象和流传的规则相同,当我们条件中出现is null,也就是试图搜索列值为空的数据行,索引路径是不出现在执行计划中的。

 

如果不使用is null,转为对取值列进行搜索,索引路径是可行的。

 

 

SQL> explain plan for select * from t where wner='PERFSTAT';

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1516787156

--------------------------------------------------------------------------------

| Id | Operation                  | Name       | Rows | Bytes | Cost (%CPU)|

--------------------------------------------------------------------------------

|  0 | SELECT STATEMENT           |            |  136 | 12648 |    5  (0)|

|  1 | TABLE ACCESS BY INDEX ROWID| T      |  136 | 12648 |    5  (0)|

|* 2 |  INDEX RANGE SCAN    | IDX_T_OWNER |  136 |      |    1  (0)|

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

  2 - access("OWNER"='PERFSTAT')

 

14 rows selected

 

 

对应is null条件,还存在一个is not null条件。如果选择率合适,is not null执行计划中时会带入索引路径吗?

 

 

SQL> explain plan for select * from t where owner is not null;

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 3329754318

--------------------------------------------------------------------------------

| Id | Operation                  | Name       | Rows | Bytes | Cost (%CPU)|

--------------------------------------------------------------------------------

|  0 | SELECT STATEMENT           |            | 51297 | 4658K|   49  (0)|

|  1 | TABLE ACCESS BY INDEX ROWID| T          | 51297 | 4658K|   49  (0)|

|* 2 |  INDEX FULL SCAN          | IDX_T_OWNER |  139 |      |    1  (0)|

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

  2 - filter("OWNER" IS NOT NULL)

 

14 rows selected

 

 

 

一系列的实验,结论是:当我们在where语句中加入is null条件时,对应列索引是不会出现在执行计划中的。Is not null条件在选择率合适的情况下,还是可能引入索引执行计划的。

 

原因分析

 

 

is null不走索引和is not null走索引这个现象,我们可以看出问题的一些端倪。Is null虽然不是通常的where条件格式,但是绝对不是引起执行计划问题的核心因素。

 

核心原因还是在于数据列中出现null值的特殊性。我们思考一下索引构建的过程,将索引列值进行建树,其中必然涉及到诸多的比较操作。Null值的特殊性就在于参与的运算大多取值为null。这样的话,null值实际上是不能参与进建索引的过程。也就是说,null值不会像其他取值一样出现在索引树的叶子节点上。

 

 

这种情况是比较容易被证明的。我们在一些null值较多的列上建索引,会发现形成的索引树体积很小,与列值不相匹配。

 

SQL> select count(*) from t where owner is not null;

 

 COUNT(*)

----------

      139

 

SQL> select num_rows from dba_indexes where index_name='IDX_T_OWNER';

 

 NUM_ROWS

----------

      139

 

 

从字典上看出,索引中对应的函数正好等于列非空的行数。证明空值的确是不会进入索引。这样is null不走索引就好理解了,因为对应的行根本就没有在索引树上,所以也就不存在执行计划中出现索引路径了。

 

 

如何选择

 

我们了解了is null的特性,那么我们如何进行列选择呢?如果我们希望is null的时候出现索引路径,应该怎么做呢?

 

答案是借助适当的默认值和详细的功能需求分析。在笔者之前的文章《非空+默认值——一种选择方案思路》(http://space.itpub.net/17203031/viewspace-692784)中已经对这个问题进行过比较详细的说明。

 

null列的处理,我们可以通过列默认值+非空字段的方法保证列不为空。这样每行数据必然出现在索引树上,对原有null的检索条件就变为等于默认值的检索条件,是可能出现索引执行计划的。但是,要注意选择的原则:

 

ü       原有对is null检索的业务需求是否强烈,是否重要。如果通常没有对该列is null的需求,或者该列绝大多数情况都是为null(即使有索引也会因为成本原因不走),那么还是不建议设置默认值方案。因为小索引树结构还是有很多优势的;

ü       在对is null选择是关键业务用例需求,并且取值null的行比较少,选择率较好的时候,才考虑使用默认值方法来进行索引优化;

 

 

进入CBO时代之后,优化器变得越来越强大,同时也越来越复杂。只有通过不断的实验,结合实际需求和优化方向,才能在资源和性能之间选择出一个最优的平衡点。

分享到:
评论

相关推荐

    导致索引失效的口诀.pdf

    在索引上进行运算都可能导致索引失效,如加、减、乘、除、is null 、is not null等。例如,SELECT * FROM table WHERE column + 1 = 10,这里的column是索引,但是由于使用了加法运算,索引就会失效。解决方法是避免...

    oracle索引失效的总结

    在WHERE子句中使用`IS NULL`或`IS NOT NULL`时,Oracle可能无法有效地使用索引。 **解决办法**: - 考虑创建一个包含NULL值的函数索引。 - 在设计数据模型时尽量减少NULL值的使用。 #### 9. 时间戳类型转换问题 ...

    windows7旗舰版————null.sys

    该资源不是解决git bash闪退。之前因为反正被一堆贴出来又不说系统环境的null.sys把自己的搞乱了,东问西问搞来了win7旗舰版能running的正常null.sys,并不是成功运行git bash的null.sys

    MySQL数据库索引失效的10种场景.zip

    如果列允许NULL值,那么索引可能不会包含所有行,对含有NULL的列进行索引查询时可能会导致索引失效。在创建索引时,考虑是否允许NULL值,或使用`NOT NULL`约束。 **4. OR逻辑运算符** 当`OR`连接两个条件时,即使这...

    mysql 索引失效详解

    MySQL 索引失效详解 MySQL 索引是一种加快数据检索速度的数据库对象。索引可以大幅度提高查询效率,但是如果不正确使用索引,可能会导致索引失效。索引失效是指MySQL 不能使用索引来加速查询,导致查询效率下降。 ...

    oracel 分区表索引失效的问题

    ### Oracle 分区表索引失效的问题 #### 一、全局索引与分区表的关系 **全局索引**(Global Index)是指索引覆盖整个表的所有数据,而不受限于分区边界。这种类型的索引通常用于非分区列或者跨分区查询。 **实验...

    MySQL里的IFNULL、NULLIF和ISNULL用法

    用到了MySql里的isnull才发现他和MSSQL里的还是有点区别,现在简单总结一下:  mysql中isnull,ifnull,nullif的用法如下:  isnull(expr) 的用法:如expr 为null,那么isnull() 的返回值为 1,否则返回值为 0。...

    数据结构C语言实现系列——线性表

    ### 数据结构C语言实现系列——线性表 #### 知识点概述 本文将详细介绍《数据结构C语言实现系列——线性表》中提到的16种线性表顺序存储操作算法,这些算法均用C语言实现。文章将对每种算法的功能、实现逻辑以及...

    深入SQLServer中ISNULL与NULLIF的使用详解

    在SQL Server中,ISNULL和NULLIF是两个非常重要的函数,它们主要用于处理NULL值,确保数据的完整性和一致性。在数据库操作中,NULL值经常会出现,尤其是在进行比较、计算或者查询时,理解并正确使用这两个函数是提升...

    导致MySQL索引失效的一些常见写法总结

    9. **NULL值处理**:索引通常不包含`NULL`值,因此`WHERE column IS NULL`的查询可能不会使用索引。 10. **分组和排序(GROUP BY 和 ORDER BY)**:如果分组或排序的列没有索引,MySQL可能需要进行临时排序,导致...

    MySQL索引失效的11种情况.docx

    如果查询条件涉及的索引列中有空值(NULL),则索引可能会失效。 **示例**: ```sql SELECT * FROM student WHERE age IS NULL; ``` ##### 2.11 索引列被显式忽略 如果查询中使用了`IGNORE INDEX`或`FORCE INDEX`等...

    oraclesql判断值为空-Oracle-sqlserver的空值(null)判断.pdf

    Oracle SQL 判断值为空OrNull 判断 Oracle SQL 中判断值为空...在 Oracle 和 SQL Server 中,我们可以使用 `NVL` 和 `ISNULL` 函数来判断值为空或 Null,並使用 `isNull` 和 `is not null` 来判断值是否为空或 Null。

    C语言系列——C 内存管理详解

    - **内存越界**:确保数组或指针操作不过界,特别是循环中的索引。 - **内存泄漏**:确保每次`malloc/new`后都有相应的`free/delete`释放内存。 - **释放后继续使用内存**:释放内存后将指针设为NULL,防止野指针...

    oracle数据库索引失效

    14. 联合索引的`IS NOT NULL`查询只要涉及到建立的索引列就会使用,但`IN NULL`查询需要与索引的第一列一起使用。 为了避免索引失效,可以采取以下策略: 1. 确保查询条件与索引列匹配,并使用索引的引导列。 2. ...

    PHP视频教程系列——总共22章节(11)

    【PHP视频教程系列——总共22章节(11)】是一个专门为学习PHP编程语言而设计的视频教程资源。这个系列涵盖了从基础到进阶的PHP知识,旨在帮助初学者和有一定经验的开发者深入理解PHP的核心概念和技术。在这个第11...

    ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数

    ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数的几种用法,

    Java工具类

    public static boolean isNull(Object a) { String b = toString(a); return isNull(b); } public static boolean isNull(String a) { a = ("" + a).trim(); if (a == null || "".equals(a) || "null".equals...

    【mysql面试题】100道MySQL数据库经典面试题解析

    索引字段上使用is null, is not null,可能导致索引失效。   左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。   mysql估计使用全表扫描要比使用索引快,则不使用索引。  索引...

Global site tag (gtag.js) - Google Analytics