Null值索引
准备样表
SCOTT@PROD>create table t as select * from all_objects;
Table created.
SCOTT@PROD>select count(*) from t;
COUNT(*)
----------
5985
SCOTT@PROD>update t set OBJECT_TYPE=null where OBJECT_TYPE='INDEX';
2 rows updated.
我们建立一个普通的单列索引
SCOTT@PROD>create index t_obj_type_idx on t(OBJECT_TYPE);
Index created.
SCOTT@PROD>set autot traceonly;
SCOTT@PROD>select count(*) from t where OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 25 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 11 | | |
|* 2 | TABLE ACCESS FULL| T | 1 | 11 | 25 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE" IS NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
82 consistent gets
0 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可见普通的单列索引无法记录null值
SCOTT@PROD>drop index t_obj_type_idx;
Index dropped.
我们建立一个复合索引,第二列为常数值,常数列没有意义,但是在有常数列的情况下,第一列的null会录入index
SCOTT@PROD>create index t_obj_type_idx on t(OBJECT_TYPE,1);
Index created.
SCOTT@PROD>select count(*) from t where OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 3976877961
--------------------------------------------------------------------------------
----
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
----
| 0 | SELECT STATEMENT | | 1 | 11 | 3 (0)| 00:00:
01 |
| 1 | SORT AGGREGATE | | 1 | 11 | |
|
|* 2 | INDEX RANGE SCAN| T_OBJ_TYPE_IDX | 1 | 11 | 3 (0)| 00:00:
01 |
--------------------------------------------------------------------------------
----
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_TYPE" IS NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
25 recursive calls
0 db block gets
102 consistent gets
1 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
我们再尝试一下一般的复合索引
SCOTT@PROD>create index t_obj_type_idx on t(OBJECT_TYPE,OBJECT_NAME);
Index created.
SCOTT@PROD>set autot traceonly;
SCOTT@PROD>select count(*) from t where OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 3976877961
--------------------------------------------------------------------------------
----
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
----
| 0 | SELECT STATEMENT | | 1 | 11 | 3 (0)| 00:00:
01 |
| 1 | SORT AGGREGATE | | 1 | 11 | |
|
|* 2 | INDEX RANGE SCAN| T_OBJ_TYPE_IDX | 1 | 11 | 3 (0)| 00:00:
01 |
--------------------------------------------------------------------------------
----
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_TYPE" IS NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
25 recursive calls
0 db block gets
102 consistent gets
1 physical reads
0 redo size
526 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可见复合索引含null值在首列的情况下 ,null值会被记录进index
那不在首列的情况下,是否会被记录呢
SCOTT@PROD>create index t_idx on t(OWNER,OBJECT_TYPE);
Index created.
SCOTT@PROD>select count(*) from t where OWNER='SYS' and OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 1058879072
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 28 | 9 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 28 | | |
|* 2 | INDEX FAST FULL SCAN| T_IDX | 3 | 84 | 9 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE" IS NULL AND "OWNER"='SYS')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
25 recursive calls
0 db block gets
125 consistent gets
20 physical reads
0 redo size
525 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可见复合索引是会记录null值的
附:
何时oracle会通过复合索引查询复合索引上的非首列
复合索引上的非首列单独作为谓词的过滤条件时,大部分情况下是不能走索引的,但是万事有例外
SCOTT@PROD>select count(*) from t where OBJECT_TYPE='VIEW';
Execution Plan
----------------------------------------------------------
Plan hash value: 1058879072
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 9 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 11 | | |
|* 2 | INDEX FAST FULL SCAN| T_IDX | 1245 | 13695 | 9 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='VIEW')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
88 consistent gets
0 physical reads
0 redo size
527 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可见走了索引,这其实是聚集函数的原因,count(*)只查询记录数,不需要回表
SCOTT@PROD>select * from t where OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 158 | 25 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 1 | 158 | 25 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_TYPE" IS NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
146 consistent gets
0 physical reads
0 redo size
1736 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed
可见在不使用聚集函数时,是无法使用符合索引的
SCOTT@PROD>select sum(object_id) from t where OBJECT_TYPE is null;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 25 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 24 | | |
|* 2 | TABLE ACCESS FULL| T | 1 | 24 | 25 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE" IS NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
145 consistent gets
0 physical reads
0 redo size
534 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
使用了聚集函数还是不走索引,说明真正的原因是索引回表,当没有索引回表时,符合索引的非首列在单独作为过滤条件时是会走索引的