【Oracle index】自定义函数索引使用及其注意点
转:http://blog.iyunv.com/uid-7655508-id-3708041.html
当我们对列使用了函数运算之后,如果此列没有函数索引,那么普通索引是无效的。比如where substr(name,1,3)='abc';如果建立了create INDEX idx_t ON t(NAME);
那么谓词是无法使用此索引做范围扫描的。在oracle中允许定义函数索引(FUNCTION BASED INDEX,简称FBI),函数索引可以是基于内置函数的,也可以是自定义函数的,
本文主要讲述基于自定义函数的索引用法及其注意点。
--使用自定义函数索引,必须加DETERMINISTIC,并且实际对应一样的输入参数,返回的结果就是一样的,否则会导致错误
dingjun123@ORADB> CREATE OR REPLACE FUNCTION get_date(param_in VARCHAR2)
2 RETURN DATE DETERMINISTIC
3 AS
4 BEGIN
5 RETURN TO_DATE(param_in,'yyyy');
6 END;
7 /
dingjun123@ORADB> INSERT INTO tt
2 SELECT LEVEL FROM dual CONNECT BY LEVEL < 1000;
999 rows created.
--DBMS_APPLICATION_INFO包监控函数的调用次数
dingjun123@ORADB> CREATE OR REPLACE FUNCTION func_tt(x IN VARCHAR2)
2 RETURN VARCHAR2 DETERMINISTIC AS
3 BEGIN
4 DBMS_APPLICATION_INFO.set_client_info(USERENV('client_info')+1 );
5 RETURN 'o' || x;
6 END;
7 /
Function created.
--使用的时候不再调用函数,因为已经调用过函数,函数运算的结果已经存储到索引中了
dingjun123@ORADB> SELECT * FROM tt WHERE func_tt(NAME) = 'o1';
1 row selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 6977672
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 20090 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TT | 10 | 20090 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TT | 4 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DINGJUN123"."FUNC_TT"("NAME")='o1')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
24 recursive calls
0 db block gets
14 consistent gets
0 physical reads
0 redo size
417 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
dingjun123@ORADB> CREATE OR REPLACE FUNCTION func_tt(x IN VARCHAR2)
2 RETURN VARCHAR2 DETERMINISTIC AS
3 BEGIN
4 DBMS_APPLICATION_INFO.set_client_info(USERENV('client_info')+1 );
5 RETURN 'a' || x;
6 END;
7 /
Function created.
--查询不对,函数应该运算结果'o1'应该没有行,但是因为索引没有被rebuild
dingjun123@ORADB> SELECT * FROM tt WHERE func_tt(NAME) = 'o1';
NAME
----------
1
1 row selected.
--强制全表扫描,正确
dingjun123@ORADB> SELECT/*+full(tt)*/ * FROM tt WHERE func_tt(NAME) = 'o1';
no rows selected
--rebuild索引后也正确
dingjun123@ORADB> alter index idx_tt rebuild;
Index altered.
dingjun123@ORADB> set autotrace traceonly
dingjun123@ORADB> SELECT * FROM tt WHERE func_tt(NAME) = 'o1';
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 6977672
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 20090 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TT | 10 | 20090 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TT | 4 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DINGJUN123"."FUNC_TT"("NAME")='o1')