eygle.com   eygle.com
eygle.com eygle
eygle.com  
 

« 使用Index提示 强制使用索引 | Blog首页 | 要发现人家的优点你才会觉得幸福 »

索引与Null值对于Hints及执行计划的影响
modb.pro

由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,某些Oracle查询不会使用索引.

很多时候,我们看似可以使用全索引扫描(Full Index Scan)的情况,可能Oracle就会因为Null值的存在而放弃索引.

在此情况下即使使用Hints,Oracle也不会使用索引,其根本原因就是因为Null值的存在.

我们看以下测试.

username字段为Not Null时,Index Hints可以生效.

SQL> create table t as select username,password from dba_users;
Table created.
SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 USERNAME                                  NOT NULL VARCHAR2(30)
 PASSWORD                                           VARCHAR2(30)
SQL> create index i_t on t(username);
Index created.
SQL> set autotrace trace explain
SQL> select * from t where username='EYGLE';
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    34 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    34 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("USERNAME"='EYGLE')
Note
-----
   - dynamic sampling used for this statement
SQL> set linesize 120
SQL> select /*+ index(t,i_t) */ * from t where username='EYGLE';
Execution Plan
----------------------------------------------------------
Plan hash value: 2928007915
------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |    34 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |     1 |    34 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | I_T  |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("USERNAME"='EYGLE')
Note
-----
   - dynamic sampling used for this statement

当索引字段允许为Null时,Oracle放弃此索引:

SQL> alter table t modify (username null);
Table altered.
SQL> select /*+ index(t,i_t) */ * from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    27 |   918 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| T    |    27 |   918 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement 

当该字段为Not Null时,索引可以被强制使用:

SQL> alter table t modify (username not null);
Table altered.
SQL> select /*+ index(t,i_t) */ * from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 3593393735
------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |    27 |   918 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |    27 |   918 |     2   (0)| 00:00:01 |
|   2 |   INDEX FULL SCAN           | I_T  |    27 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement
 

这就是Null值对于索引及查询的影响.

 


历史上的今天...
    >> 2012-02-22文章:
    >> 2011-02-22文章:
    >> 2009-02-22文章:
    >> 2008-02-22文章:
           What's Mean "reliable message"?
    >> 2005-02-22文章:

By eygle on 2006-02-22 17:19 | Comments (4) | SQL.PLSQL | 689 |

4 Comments

ref:"由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,Oracle查询不会使用索引."
这种情况只影响强制使用索引hints而又无此字段的where条件时,当select语句中的where条件包含此字段的expression时一样可以使用此索引!
反之,按本文的说法,我们岂不是只能在非空字段上建索引了?!事实是我们可以在我们任意想要建索引的字段上建索引,只要你认为必要,无需关注其是否not null!
不同的是,is null条件是当然是不查B*Tree索引的,Bitmap索引则可以。

ref:"由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,Oracle查询不会使用索引."
这种情况只影响强制使用索引hints而又无此字段的where条件时,当select语句中的where条件包含此字段的expression时一样可以使用此索引!
反之,按本文的说法,我们岂不是只能在非空字段上建索引了?!事实是我们可以在我们任意想要建索引的字段上建索引,只要你认为必要,无需关注其是否not null!
不同的是,is null条件当然是不查B*Tree索引的,Bitmap索引则可以。

你说的不错,这句话说起来很绕口,当初没有说的严谨.

谢谢指出.


CopyRight © 2004~2020 云和恩墨,成就未来!, All rights reserved.
数据恢复·紧急救援·性能优化 云和恩墨 24x7 热线电话:400-600-8755 业务咨询:010-59007017-7040 or 7037 业务合作: marketing@enmotech.com