函数索引是Oracle索引中比较特殊的,我们这里讨论函数索引中部分行索引的使用。
部分行索引顾名思义仅就表中的一部分记录做索引,请看代码示例:
drop table test;
create table test (t1 int, t2 char(1));
declare
i int :=0;
begin
while i<100000
loop
insert into test values( i, ‘N’);
i:=i+1;
commit;
end loop;
end;
在test表上插入大量t2为N的行,并插入少量t2为Y的行
create index ind_t2y on test( case t2 when ‘Y’ then t2 end);
SQL> select count(*) from test;
COUNT(*)
———-
100004
表上供有100004条数据
SQL> select count(*) from test where t2=’Y’;
COUNT(*)
———-
4
为t2列为’Y’的共有4条。
我们来分析该索引:
SQL> analyze index ind_t2y validate structure;
索引已分析
SQL> select lf_rows from index_stats;
LF_ROWS
———-
4
可以看到确实仅记录了4条记录。
我们尝试利用此部分行索引:
SQL> set autotrace on;
SQL> select count(*) from test where t2=’Y’;
COUNT(*)
———-
4
Execution Plan
———————————————————-
Plan hash value: 1950795681
—————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————
| 0 | SELECT STATEMENT | | 1 | 3 | 43 (12)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | TABLE ACCESS FULL| TEST | 2 | 6 | 43 (12)| 00:00:01 |
—————————————————————————
Predicate Information (identified by operation id):
—————————————————
2 – filter(“T2″=’Y’)
Note
—–
– dynamic sampling used for this statement
Statistics
———————————————————-
0 recursive calls
0 db block gets
171 consistent gets
0 physical reads
0 redo size
515 bytes sent via SQL*Net to client
469 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
没有如预期地使用索引,我们加上hint 再试试
SQL> select /*+ index(test ind_t2y) */ count(*) from test where t2=’Y’;
COUNT(*)
———-
4
Execution Plan
———————————————————-
Plan hash value: 2501600095
—————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————-
| 0 | SELECT STATEMENT | | 1 | 3 | 2 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 6 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | IND_T2Y | 98705 | | 1 (0)| 00:00:01 |
—————————————————————————————-
Predicate Information (identified by operation id):
—————————————————
2 – filter(“T2″=’Y’)
Note
—–
– dynamic sampling used for this statement
Statistics
———————————————————-
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
515 bytes sent via SQL*Net to client
469 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
在使用部分行索引的情况下逻辑读大大下降了。
在不加hint的情况下优化器似乎永远无法做出正确的选择,即便修改了CBO相关的参数:
SQL> alter system set optimizer_index_cost_adj=1;
System altered.
SQL> select t2 from test where t2=’Y’;
T
–
Y
Y
Y
Y
Execution Plan
———————————————————-
Plan hash value: 1357081020
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 2 | 6 | 43 (12)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 2 | 6 | 43 (12)| 00:00:01 |
————————————————————————–
仅在where 子句中指定了case when then模式时,优化器自觉地使用了该部分行索引:
SQL> select * from test where case t2 when ‘Y’ then t2 end =’Y’;
T1 T
———- –
100001 Y
100002 Y
100003 Y
100004 Y
Execution Plan
———————————————————-
Plan hash value: 837354983
—————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————
| 0 | SELECT STATEMENT | | 2 | 32 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 32 | 1 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_T2Y | 1 | | 1 (0)| 00:00:01 |
—————————————————————————————
Predicate Information (identified by operation id):
—————————————————
2 – access(CASE WHEN “T2″=’Y’ THEN “T2” END =’Y’)
Note
—–
– dynamic sampling used for this statement
Statistics
———————————————————-
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
650 bytes sent via SQL*Net to client
469 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed
部分行索引在特定情况下(譬如某表中仅少数特定行有大量查询更新操作)可以发挥非常巨大的作用。
Comment