Sunday 25 September 2011

Oracle SQL "like clause" uses full table scan

It is normal behaviour within Oracle to do full table scan if 'like' clause is used to perform searches in where clause.
A sql statement as below will still perform FTS even if the column col2 is indexed.
select * from tab1 where col2 like 'Test%';

In order to let Oracle use index when indexed column is used in 'like' clause, you should implement Oracle Text feature and use 'contains' clause instead of like 'clause'.

Another way to do this without Oracle text is to use function based index which I will show below.

Below is my 1st test case with normal index:
1. Create dummy table and populate it with some test data.
SQL> create table tab1 (col1 number,col2 varchar2(200));
Table created.

SQL> begin
  2  for i in 1..1000 loop
  3  insert into tab1 values (i,'Test full scan');
  4  end loop;

  5  insert into tab1 values (1001,'Test1 full scan');
  6  end;
  7  /

PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.

2. Create index
create index idx1 on tab1(col2);

3. Generate execution plan of sql to see whether index gets used or not:
set autotrace traceonly explain
select * from tab1 where upper(col2) like 'TEST1%';
Execution Plan
----------------------------------------------------------
Plan hash value: 2211052296

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


As you can see, the Full Table Scan is done.

Now, lets try to create a function based index and see how that works.
1. Drop the old index
drop index idx1;

2. Create function based index
create index idx1 on tab1 (upper(col2));

3. Generate the execution plan of the same SQL:
set autotrace traceonly explain
select * from tab1 where upper(col2) like 'TEST%';
------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |   115 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1 |     1 |   115 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX1 |     9 |       |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------


And walla!!! The index gets used.

Please note that the function based index will only get used if the 'like' clause will have a wildcard '%' character at the end of the string. It will still do full table scan if the wildcard character is placed in the begining of the string. If that is the case, then I storngly suggest that you implement and use Oracle Text feature.

No comments:

Post a Comment