2013-07-16 62 views
0

我想创建一个基于应用函数的结果的索引,我必须提取一个数字。如何制定确定性功能?

Example String: ...someText...&idDocunet=799493...someText... 
           [799493] <- Note the number 
The function: replace(regexp_substr(parametros, '&idDocunet=\d+'), 'idDocunet=', NULL) 
The index: create index example on MY_TABLE (replace(regexp_substr(parametros, '&idDocunet=\d+'), 'idDocunet=', NULL)); 

但是当我运行此查询:

SELECT * 
FROM my_table 
WHERE replace(regexp_substr(parametros, '&idDocunet=\d+'), 'idDocunet=', NULL) IS NOT NULL. 

或者这一个

SELECT * 
FROM my_table 
WHERE replace(regexp_substr(parametros, '&idDocunet=\d+'), 'idDocunet=', NULL) = 799493 

或作出加入...

索引不使用,它执行每次都进行全表扫描。我相信索引是确定性的,因为它总是会返回数字,或者为null,但我不知道表达式是否太复杂以至于无法使用。我也尝试将代码移到一个函数中,但它是一样的。我相信关键在于这个确定性的东西(我做错了吗?)和/或原始列上具有空值的表。我怎样才能保证索引被使用?这是功能:

create or replace function extraer_doc_id(viParam VARCHAR2) return varchar2 is 
begin 
    RETURN replace(regexp_substr(viParam, '&idDocunet=\d+'), 'idDocunet=', NULL); 
end extraer_doc_id; 

我也执行该

ANALYZE TABLE my_table COMPUTE STATISTICS; 

但它似乎并不重要。

回答

3

要创建确定性函数,请在返回类型声明旁边使用DETERMINISTIC子句, 请参阅语法here

create or replace function extraer_doc_id(viParam VARCHAR2) 
    return varchar2 
    DETERMINISTIC 
is 
begin 
    RETURN replace(regexp_substr(viParam, '&idDocunet=\d+'), 'idDocunet=', NULL); 
end extraer_doc_id; 

您创建了引用my_column场函数的索引:

replace(regexp_substr(**my_column**, '&idDocunet=\d+'), 'idDocunet=', NULL) 

但查询的where子句中使用的是一个函数,从指数的功能不同(不同的列):

WHERE replace(regexp_substr(**parametros**, '&idDocunet=\d+'), 'idDocunet=', NULL) = 799493 

因此Oracle不能使用这个索引这个曲这些表达是不同的。 也不要使用ANALYZE TABLE,这个命令在10g中已被废弃,用DBMS_STATS代替:

+0

嗨,对于“parametros”的事情,我忘了更新这个例子,当我用“my_column”在这里写的时候,我真的用同样的函数测试过,但索引没有被使用。我将用我的函数中的确定性子句进行测试,但它应该与查询一起工作,对吧? – Roger

2

要使用基于函数的索引,你应该:

  • 使用自己的函数DETERMINISTIC条款;
  • 查询必须使用与您提到的创建索引相同的函数和列。

例如:

set define off 
drop table test; 
create table test (s varchar2(100)) 
/

create or replace function getDocId(p varchar2) 
return number 
deterministic 
is 
begin 
    return to_number(regexp_replace(p, '^.*&idDocunet=(\d+).*$', '\1')); 
end getDocId; 
/

create index test_fbi on test(getDocId(s)) 
/

insert into test values('...someText...&idDocunet=799493...someText...') 
/

现在让我们一计划:

explain plan for 
select * 
    from test 
where getdocid(s) = 1 
/

select * from table(dbms_xplan.display); 

PLAN_TABLE_OUTPUT                                                                       
--------------------------------------------------------------------------------------- 
Plan hash value: 3113607502                                                                     

----------------------------------------------------------------------------------------                                                      
| Id | Operation     | Name  | Rows | Bytes | Cost (%CPU)| Time  |                                                      
----------------------------------------------------------------------------------------                                                      
| 0 | SELECT STATEMENT   |   |  1 | 65 |  1 (0)| 00:00:01 |                                                      
| 1 | TABLE ACCESS BY INDEX ROWID| TEST  |  1 | 65 |  1 (0)| 00:00:01 |                                                      
|* 2 | INDEX RANGE SCAN   | TEST_FBI |  1 |  |  1 (0)| 00:00:01 |                                                      
----------------------------------------------------------------------------------------                                                      

Predicate Information (identified by operation id):                                                               
---------------------------------------------------                                                               

    2 - access("TEST"."GETDOCID"("S")=1)                                                                  

Note                                                                           
-----                                                                           
    - dynamic sampling used for this statement (level=2)                                                              

18 rows selected 

正如你可以看到,使用索引。