Question

I'm trying to create an index based on the result of a function applied a column where I have to extract a number.

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));

But when I run this query:

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

Or this one

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

Or make a join...

The index is not used and it performs a full table scan every time. I believe the index is deterministic because it will always return the number, or null but I don't know if the expression is just too complex for it to use. I also tried to move the code to a function but it is the same. I believe the key is in this deterministic thing (I'm doing it wrong?) and/or the table having null values on the original column. How can I assure that the index is used? this is the function:

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;

I also executed this

ANALYZE TABLE my_table COMPUTE STATISTICS;

But it doesn't seem to matter.

Was it helpful?

Solution

To create a deterministic function, use DETERMINISTIC clause next to return type declaration, see syntax 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;

You created a function based index that references my_column field:

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

but in the where clause of the query you are using a function that is different from the function in the index (different column):

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

so Oracle cannot use this index for this query, these expressions are different. Also do not use ANALYZE TABLE, this command was deprecated in 10g, use DBMS_STATS instead:

OTHER TIPS

To use function-based indexes you should:

  • use DETERMINISTIC clause in your own function;
  • query must use the same function(s) and column(s) as those you mentioned creating an index.

For example:

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...' )
/

Now let's get a plan:

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 

As you can see, the index is used.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top