2013-07-16 121 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 

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