在NULL值与索引(一)中讲述了null值与索引的一些基本情况。其主要的内容为,基于允许存在null值的索引列,其索引值不会被存储;其次
是由于这个特性导致了我们在使用is null时索引失效的情形;最后则是描述的通过为null值列添加not null约束来使得is null走索引。尽管我
们可以通过添加not null来解决is null走索引,当现实中的情况是仍然很多列根本是无法确定的,而必须保持其null特性。对于此种情形该如
何解决呢?
一、通过基于函数的索引来使得is null使用索引
二、使用伪列创建基于函数的索引来使得is null使用索引
-
-
scott@ORCL> create index i_new_t2_obj_id on t2(obj_id,-1);
-
-
Index created.
-
-
-
scott@ORCL> exec dbms_stats.gather_index_stats('SCOTT','I_NEW_T2_OBJ_ID');
-
-
PL/SQL procedure successfully completed.
-
-
-
scott@ORCL> select count(*) from t2 where obj_id is null;
-
-
Execution Plan
-
-
Plan hash value: 801885198
-
-
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
-
| 0 | SELECT STATEMENT | | 1 | 5 | 2 (0)| 00:00:01 |
-
| 1 | SORT AGGREGATE | | 1 | 5 | | |
-
|* 2 | INDEX RANGE SCAN| I_NEW_T2_OBJ_ID | 99 | 495 | 2 (0)| 00:00:01 |
-
-
-
Predicate Information (identified by operation id):
-
-
-
2 - access("OBJ_ID" IS NULL)
-
-
-
scott@ORCL> select index_name,index_type,blevel,leaf_blocks,num_rows,status,distinct_keys
-
2 from user_indexes where table_name='T2';
-
-
INDEX_NAME INDEX_TYPE BLEVEL LEAF_BLOCKS NUM_ROWS STATUS DISTINCT_KEYS
-
-
I_FN_T2_OBJ_ID FUNCTION-BASED NORMAL 1 26 11719 VALID 11621
-
I_NEW_T2_OBJ_ID FUNCTION-BASED NORMAL 1 32 11719 VALID 11621
-
I_T2_OBJ_ID NORMAL 1 25 11620 VALID 11620
-
-
-
-
-
-
三、NULL值与索引衍生特性
-
-
-
-
-
-
-
-
scott@ORCL> update t2 set obj_id=1 where obj_id is not null;
-
-
11620 rows updated.
-
-
-
scott@ORCL> update t2 set obj_id = 0 where obj_id is null;
-
-
99 rows updated.
-
-
scott@ORCL> commit;
-
-
-
scott@ORCL> exec dbms_stats.gather_table_stats('SCOTT','T2',cascade=>true);
-
-
PL/SQL procedure successfully completed.
-
-
-
scott@ORCL> select obj_id,count(*) from t2 group by obj_id;
-
-
OBJ_ID COUNT(*)
-
-
1 11620
-
0 99
-
-
-
-
scott@ORCL> create index i_fn2_t2_obj_id on t2(decode(obj_id,0,0,null));
-
-
Index created.
-
-
-
scott@ORCL> exec dbms_stats.gather_index_stats('SCOTT','I_FN2_T2_OBJ_ID');
-
-
PL/SQL procedure successfully completed.
-
-
-
scott@ORCL> set autot trace exp;
-
scott@ORCL> select count(*) from t2 where decode(obj_id,0,0,null) = 0;
-
-
Execution Plan
-
-
Plan hash value: 1461308992
-
-
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
-
| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 |
-
| 1 | SORT AGGREGATE | | 1 | 3 | | |
-
|* 2 | INDEX RANGE SCAN| I_FN2_T2_OBJ_ID | 98 | 294 | 1 (0)| 00:00:01 |
-
-
-
Predicate Information (identified by operation id):
-
-
-
2 - access(DECODE("OBJ_ID",0,0,NULL)=0)
-
-
-
scott@ORCL> select count(*) from t2 where obj_id = 0;
-
-
Execution Plan
-
-
Plan hash value: 1804118247
-
-
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
-
| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 |
-
| 1 | SORT AGGREGATE | | 1 | 3 | | |
-
|* 2 | INDEX RANGE SCAN| I_T2_OBJ_ID | 99 | 297 | 1 (0)| 00:00:01 |
-
-
-
Predicate Information (identified by operation id):
-
-
-
2 - access("OBJ_ID"=0)
-
-
-
scott@ORCL> select * from t2 where obj_id = 1;
-
-
Execution Plan
-
-
Plan hash value: 1513984157
-
-
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
-
| 0 | SELECT STATEMENT | | 11620 | 249K| 14 (8)| 00:00:01 |
-
|* 1 | TABLE ACCESS FULL| T2 | 11620 | 249K| 14 (8)| 00:00:01 |
-
-
-
Predicate Information (identified by operation id):
-
-
-
1 - filter("OBJ_ID"=1)
-
-
-
scott@ORCL> select index_name,index_type,blevel,leaf_blocks,num_rows,status,distinct_keys
-
2 from user_indexes where table_name='T2';
-
-
INDEX_NAME INDEX_TYPE BLEVEL LEAF_BLOCKS NUM_ROWS STATUS DISTINCT_KEYS
-
-
I_FN_T2_OBJ_ID FUNCTION-BASED NORMAL 1 40 11719 VALID 2
-
I_NEW_T2_OBJ_ID FUNCTION-BASED NORMAL 1 52 11719 VALID 2
-
I_FN2_T2_OBJ_ID FUNCTION-BASED NORMAL 0 1 99 VALID 1
-
I_T2_OBJ_ID NORMAL 1 40 11719 VALID 2
-
-
-
-
-
四、总结
1、对于用于连接或经常被谓词使用到的列应尽可能避免NULL值属性,因为它容易导致索引失效。
2、为需要使用NULL值的列添加缺省值(alter table tb modify(col default 'Y'))。
3、如果NULL值不可避免也不能使用缺省值,应考虑为该常用列使用nvl函数创建索引,或使用伪列来创建索引以提高查询性能。
4、对于复合索引应保证索引中至少有一列不为NULL值,还是因为全部列为NULL时不被索引存储,以保证使用is null是可以使用索引。
5、对于复合索引应保证索引列应使用数据类型长度最小的列来添加not null约束应节省磁盘空间。