当前位置: DBARoad > 基础知识 > 文章正文

单列索引与NULL值

                    作者 :OoNiceDream【转载时请务必以超链接形式标明文章原始出处和作者信息】
                    链接:http://www.dbaroad.me/archives/2009/06/index_with_null_1.html

常见的B-Tree单列索引中,并不会记录null值的索引条目,因而is null等条件的查询走不了索引,走的是全表扫,而Bitmap索引则不同,它会记录NULL值的索引条目:

B-Tree Index:

SQL> create table test_btree (name varchar2(10) default null);
 
Table created.
 
SQL> begin 
  2  for i in 1..100 loop
  3  insert into test_btree values(default);
  4  commit;
  5  end loop;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
SQL> create index ind_btree on test_btree(name);
 
Index created.
 
SQL> select object_id from dba_objects
  2  where object_name='IND_BTREE';
 
 OBJECT_ID
----------
    109139
 
SQL> alter session set events 'immediate trace name treedump level 109139';
 
Session altered.

叶子节点中未记录有索引条目:

----- begin tree dump
leaf: 0x410eea 4263658 (0: nrow: 0 rrow: 0)
----- end tree dump

Bitmap Index

SQL> create table test_bitmap (name varchar2(10) default null);
 
Table created.
 
SQL> begin 
  2  for i in 1..100 loop
  3  insert into test_bitmap values(default);
  4  commit;
  5  end loop;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
SQL> create bitmap index ind_bitmap on test_bitmap(name);
 
Index created.
 
SQL> select object_id from dba_objects
  2   where object_name='IND_BITMAP';
 
 OBJECT_ID
----------
    109141
 
SQL> alter session set events 'immediate trace name treedump level 109141';
 
Session altered.

叶子节点中记录有索引条目:

----- begin tree dump
leaf: 0x410f02 4263682 (0: nrow: 1 rrow: 1)
----- end tree dump 
 
SQL> select 
  2  dbms_utility.data_block_address_file(4263682) file_id#,
  3  dbms_utility.data_block_address_block(4263682) block_id# 
  4  from dual;
 
  FILE_ID#  BLOCK_ID#
---------- ----------
         1      69378
 
SQL> alter system dump datafile 1 block 69378;
 
System altered.
 
Leaf block dump
===============
header address 9223376400541909084=0x800003f80005805c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 1
kdxcofbo 38=0x26
kdxcofeo 7983=0x1f2f
kdxcoavs 7945
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8016
row#0[7983] flag: ------, lock: 0, len=33
col 0; NULL
col 1; len 6; (6):  00 41 0e fa 00 00
col 2; len 6; (6):  00 41 0e fa 00 67
col 3; len 15; (15):  cf ff ff ff ff ff ff ff ff cc ff ff ff ff 0f
----- end of leaf block dump -----

因而对于is null等条件的查询,B-Tree类型的索引是用不上的,而Bitmap索引则可以:

SQL> select count(*) from test_btree
  2  where name is null;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2736914969
 
---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     1 |     7 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |            |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS FULL| TEST_BTREE |   100 |   700 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("NAME" IS NULL)
 
Note
-----
   - dynamic sampling used for this statement
 
SQL> select count(*) from test_bitmap
  2  where name is null;    
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2521385644
 
--------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |     1 |     7 |     1   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE               |            |     1 |     7 |            |          |
|   2 |   BITMAP CONVERSION COUNT     |            |   100 |   700 |     1   (0)| 00:00:01 |
|*  3 |    BITMAP INDEX FAST FULL SCAN| IND_BITMAP |       |       |            |          |
--------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - filter("NAME" IS NULL)
 
Note
-----
   - dynamic sampling used for this statement

在B-Tree索引中,INDEX FAST FULL SCAN要求索引中至少有一列是带有not null约束的,BITMAP索引显然就不受这一约束了。

另外有一点需要注意的是,在唯一索引中,Oracle认为NULL与NULL是不同的:

sys@ORCL>create table t (a number);
 
Table created.
 
sys@ORCL>create unique index ind_t on t(a);
 
Index created.
 
sys@ORCL>insert into t values(1);
 
1 row created.
 
sys@ORCL>insert into t values(1);
insert into t values(1)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.IND_T) violated
 
 
sys@ORCL>insert into t values(null);
 
1 row created.
 
sys@ORCL>insert into t values(null);
 
1 row created.
 
sys@ORCL>commit;
 
Commit complete.

但对group by 语句来说却是一样的:

sys@ORCL>select count(*),a from t group by a;
 
  COUNT(*)          A
---------- ----------
         1          1
         2

因而我们在创建唯一索引时,常常要求至少有一列是NOT NULL的。

— The End —

关键字:
喜欢DBARoad的文章,那就通过 RSS Feed 功能订阅阅读吧!

我要评论

*

* 绝不会泄露


  • 订阅


      抓虾
      google reader
      my yahoo
      bloglines
      鲜果
      有道

站内搜索



返回首页 | 关于我 | 联系我 | 广告合作 | 网站地图 | 友情链接 | 版权声明 |