Function-Based Indexes

Posted on


Home » Articles » 8i » Right here

Serve as-Based totally Indexes

Historically, appearing a occupation on an listed column within the the place clause of a question assured an index would
no longer be worn. Oracle 8i presented Serve as-Based totally Indexes to counter this infection. Instead than indexing a column, you
index the occupation on that column, storing the fabricated from the occupation, no longer the latest column information. When a question is handed
to the server that would have the benefit of that index, the question is rewritten to permit the index to be worn. Please see code
samples give an instance of the utility of Serve as-Based totally Indexes.

Manufacture Check Desk

First we create a take a look at desk and populate it with plenty information in order that utility of an index could be tremendous.

CREATE TABLE user_data (
 identity          NUMBER(10)    NOT NULL,
 first_name  VARCHAR2(40)  NOT NULL,
 last_name   VARCHAR2(40)  NOT NULL,
 gender      VARCHAR2(1),
 dob         DATE
);

BEGIN
  FOR cur_rec IN 1 .. 2000 LOOP
    IF MOD(cur_rec, 2) = 0 THEN
      INSERT INTO user_data 
      VALUES (cur_rec, 'John' || cur_rec, 'Doe', 'M', SYSDATE);
    ELSE
      INSERT INTO user_data 
      VALUES (cur_rec, 'Jayne' || cur_rec, 'Doe', 'F', SYSDATE);
    END IF;
    COMMIT;
  END LOOP;
END;
/

EXEC DBMS_STATS.gather_table_stats(USER, 'user_data', cascade => TRUE);

At this level the desk isn’t listed so we’d be expecting a complete desk scan for any question.

SET AUTOTRACE ON
SELECT *
FROM   user_data
WHERE  UPPER(first_name) = 'JOHN2';

Execution Plan
----------------------------------------------------------
Plan hash price: 2489064024

-------------------------------------------------------------------------------
| Identity  | Operation         | Title      | Rows  | Bytes | Value (%CPU)| Week     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |    20 |   540 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| USER_DATA |    20 |   540 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Manufacture Common Index

If we now form a common index at the FIRST_NAME column we see that the index isn’t worn.

CREATE INDEX first_name_idx ON user_data (first_name);
EXEC DBMS_STATS.gather_table_stats(USER, 'user_data', cascade => TRUE);

SET AUTOTRACE ON
SELECT *
FROM   user_data
WHERE  UPPER(first_name) = 'JOHN2';

Execution Plan
----------------------------------------------------------
Plan hash price: 2489064024

-------------------------------------------------------------------------------
| Identity  | Operation         | Title      | Rows  | Bytes | Value (%CPU)| Week     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |    20 |   540 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| USER_DATA |    20 |   540 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Manufacture Serve as-Based totally Index

If we now exchange the common index with a function-based index at the FIRST_NAME column we see that the index is worn.

DROP INDEX first_name_idx;
CREATE INDEX first_name_idx ON user_data (UPPER(first_name));
EXEC DBMS_STATS.gather_table_stats(USER, 'user_data', cascade => TRUE);

-- Nearest releases poised those via default.
ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED; 
ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE;

SET AUTOTRACE ON
SELECT *
FROM   user_data
WHERE  UPPER(first_name) = 'JOHN2';
   
Execution Plan
----------------------------------------------------------
Plan hash price: 1309354431

----------------------------------------------------------------------------------------------
| Identity  | Operation                   | Title           | Rows  | Bytes | Value (%CPU)| Week     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |     1 |    36 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| USER_DATA      |     1 |    36 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | FIRST_NAME_IDX |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

The QUERY_REWRITE_INTEGRITY and QUERY_REWRITE_ENABLED parameters should be poised or the server won’t be able to
rewrite the queries, and can due to this fact no longer have the ability to utility the pristine index. Nearest releases have them enabled via default.

Concatenated Columns

This mode works for concatenated indexes additionally.

DROP INDEX first_name_idx;
CREATE INDEX first_name_idx ON user_data (gender, UPPER(first_name), dob);
EXEC DBMS_STATS.gather_table_stats(USER, 'user_data', cascade => TRUE);

SET AUTOTRACE ON
SELECT *
FROM   user_data
WHERE  gender="M"
AND    UPPER(first_name) = 'JOHN2';

Execution Plan
----------------------------------------------------------
Plan hash price: 1309354431

----------------------------------------------------------------------------------------------
| Identity  | Operation                   | Title           | Rows  | Bytes | Value (%CPU)| Week     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |     1 |    36 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| USER_DATA      |     1 |    36 |     3   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | FIRST_NAME_IDX |     1 |       |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Bear in mind, function-based indexes require extra aim to preserve than common indexes, so having concatenated indexes on this way might build up the occurrence of index repairs in comparison to a function-based index on a unmarried column.

For more info see:

Hope this is helping. Regards Tim…

Back to the Top.

Leave a Reply

Your email address will not be published. Required fields are marked *