Wednesday, July 7, 2010

INDEX RANGE SCAN will be skipped if first character in the string to be search will be wildcard


SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SQL> exec dbms_stats.gather_table_stats('SCOTT','EMP',cascade=>TRUE);

PL/SQL procedure successfully completed.


First of all we are testing all the index scan without using any wild card as a first character.

SQL> set autot traceonly;
SQL> select * from emp where ename LIKE 'S%OT%T%%';


Execution Plan
----------------------------------------------------------
Plan hash value: 3307655913

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

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

2 - access("ENAME" LIKE 'S%OT%T%%')
filter("ENAME" LIKE 'S%OT%T%%')


Statistics
----------------------------------------------------------
165 recursive calls
0 db block gets
30 consistent gets
0 physical reads
0 redo size
826 bytes sent via SQL*Net to client
381 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed


Now testing using first character a wild card character.
    
SQL> set autot traceonly
SQL> select * from emp where ename LIKE '%S%OT%T%%';


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 39 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------

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

1 - filter("ENAME" LIKE '%S%OT%T%%')


Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
822 bytes sent via SQL*Net to client
381 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed


It seems that whenever we are using a willcard ('%', '_') as a first character then it is skipping index scan becuase Wildchad is making the string to be search uncertain.
Let do one more experiment. Now we hide the wild card character with escape. like


SQL> select * from emp where ename LIKE '/_S%OT%T%%' escape '/';

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3307655913

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

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

2 - access("ENAME" LIKE '/_S%OT%T%%' ESCAPE '/')
filter("ENAME" LIKE '/_S%OT%T%%' ESCAPE '/')


Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1 consistent gets
0 physical reads
0 redo size
656 bytes sent via SQL*Net to client
370 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

SQL>

No comments: