Skip navigation.

Tuning a 'LIKE-clause' by using Oracle Text or Reverse Key Indexes

The LIKE-clause can ignore indexes, causing queries to run forever while doing full table scans. This document describes how to tune such SQL statements by making use of Oracle Text or reverse key indexes.

Tuning the ‘LIKE’ Clause:

Generally, search arguments in the WHERE clause such as "IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'" prevents Oracle from using an index to perform the search (however, not always).

If you use LIKE in your WHERE clause, try to specify one or more leading characters if at all possible. For example, use LIKE 'm%' and not LIKE '%m'. If you specify a leading character, Oracle has a better chance of being able to use an index to perform the query - this will increase performance and reduce the load on the database server.

To avoid such full table scans, consider the following scenarios:

Case 1: Tuning the LIKE-clause by using Oracle Text indexes

Requirements:

A. Install and configure Oracle's TEXT (done as part of the installation process).

B. Check whether Oracle TEXT is installed by looking for the 'CTXSYS' schema.

The problem

I. Create a test table:

create table t as select * from tab;
CREATE INDEX normal_index ON t
(TABLE_NAME) NOPARALLEL;

SQL> select TABLE_NAME from t where TABLE_NAME LIKE '%SEG%';
TABLE_NAME
------------------------------
D_MKTSEG
SEG$

II. Run a query to demonstrate that it will do a full table scan:

SQL> set autotrace traceonly explain
SQL> select TABLE_NAME from t where TABLE_NAME LIKE '%SEG%';

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'T'

III. Drop the index:

SQL> drop index normal_index;

Index dropped.

Solution:

I. Create an Oracle Text index on the columns that you would like to search:

SQL> create index xyz_oracle_txt_idx on t(TABLE_NAME) INDEXTYPE IS CTXSYS.CONTEXT;
Index created.

II. Change the LIKE-clause to an CONTAINS-clause - WHERE CONTAINS(TABLE_NAME, '%SEG%') > 0;

SQL> select TABLE_NAME from t WHERE CONTAINS(TABLE_NAME, '%SEG%')>0;

TABLE_NAME
------------------------------
D_MKTSEG
SEG$

III. Look at the SQL plan:

SQL> set autotrace traceonly explain
SQL> select TABLE_NAME from t WHERE CONTAINS(TABLE_NAME, '%SEG%')>0;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=24)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=
          24)

   2    1     DOMAIN INDEX OF 'XYZ_ORACLE_TXT_IDX' (Cost=0)

Much better!

Case 2: Tuning the LIKE-clause by using reverse key indexes

Another trick for indexing queries with a leading wildcard character (like '%SON') is to create a REVERSE index - and then programmatically reverse the LIKE-clause to read "LIKE 'NOS%'", effectively indexing on the other side of the text, clumsy, yet effective.

Steps:

1. Create reverse key index on columns that will be searched. For example, create a reverse key index on Cust_Name of the customer table:

CREATE INDEX Cust_Name_reverese_idx
ON customer(Cust_Name)
REVERSE;

2. Programmatically reverse the SQL LIKE-clause to read '%saliV%':

Existing Query:

SELECT * 
FROM customer
WHERE Cust_Name LIKE '%Vilas%'

New Query:

SELECT * 
FROM customer
WHERE Cust_Name LIKE '%saliV%';

Case 2

What do you want to explain with your CASE2?
1) It is not explaining anything
2) you are adding index but your query is not using it
3) Have you tried your query(-ies) before writing them here?

Case 2 can not work

IMHO you are mistaken.

There is NO way for Oracle to use index (normal or reversed) with LIKE '%string%' clause.

Michael

Tuning a 'LIKE-clause' by using Oracle Text or Reverse Key Index

Hi,

This is not working. I tested the code in Oracle 11g. In my case whese the normal index Like statement optimizer is using Index Full scan but when I use the Oracle Text Index optimizer is using Full Table Scan. And one more thing, in TAB dictionary the column name is TNAME not TABLE_NAME. Might be a typo.

Thanks...