如何确定功能?

时间:2013-07-16 22:26:31

标签: oracle oracle10g indexing deterministic

我正在尝试根据应用列的函数的结果创建索引,我必须提取一个数字。

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;

但似乎并不重要。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

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

  • 在您自己的函数中使用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 

如您所见,使用了索引。