Wednesday, April 13, 2016

How to properly use functions to avoid full table and index scan


1. WITHOUT INDEX

SQL> select COUNT(*) from PAYMENT_REQUESTS where DEPENDENT_CODE=1062209398;

  COUNT(*)
----------
        41

Elapsed: 00:00:06.18

Execution Plan
----------------------------------------------------------
Plan hash value: 3772329927

----------------------------------------------------------------------------------------------------
| Id  | Operation          | Name                          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                               |     1 |     2 | 67406   (1)| 00:13:29 |
|   1 |  SORT AGGREGATE    |                               |     1 |     2 |            |          |
|*  2 |   TABLE ACCESS FULL| PAYMENT_REQUESTS   |     5 |    10 | 67406   (1)| 00:13:29 |
----------------------------------------------------------------------------------------------------

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

   2 - filter("DEPENDENT_CODE"='1078754196')


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

2. AFTER CREATING INDEX "IDX_$XXX0001_ON_DEPENDENT_CODE"

SQL> select COUNT(*) from FIN_EDATT_STD_PAYMENT_REQUEST where DEPENDENT_CODE=1062209398;

  COUNT(*)
----------
         0

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 4006545759

----------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                                |     1 |     2 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |                                |     1 |     2 |            |          |
|*  2 |   INDEX RANGE SCAN| IDX_$XXX0001_ON_DEPENDENT_CODE |   120 |   240 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

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

   2 - access("DEPENDENT_CODE"='1062209398')


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


3. PLACING FUNCTION ON LEFT

What if i have to convert this number column to character. Will index still be used ? Let's give it a try.

SQL> select COUNT(*) from PAYMENT_REQUESTS where TO_CHAR(STUDENT_ID_NUM)='1062209398';

  COUNT(*)
----------
        41

Elapsed: 00:00:01.83

Execution Plan
----------------------------------------------------------
Plan hash value: 1062758856

-----------------------------------------------------------------------------------------
| Id  | Operation             | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                 |     1 |     7 |  6031   (2)| 00:01:13 |
|   1 |  SORT AGGREGATE       |                 |     1 |     7 |            |          |
|*  2 |   INDEX FAST FULL SCAN| IDX$$_13AED0003 |    30 |   210 |  6031   (2)| 00:01:13 |
-----------------------------------------------------------------------------------------

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

   2 - filter(TO_CHAR("STUDENT_ID_NUM")='1062209398')


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

You can see a fast full index scan occured and query took 1.83 seconds. This can be further improved moving funcion on Right.

4.     PLACING FUNCTION ON RIGHT

SQL> select COUNT(*) from PAYMENT_REQUESTS where DEPENDENT_CODE=TO_CHAR('1078754196');

  COUNT(*)
----------
         3

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 4006545759

----------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                                |     1 |     2 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |                                |     1 |     2 |            |          |
|*  2 |   INDEX RANGE SCAN| IDX_$XXX0001_ON_DEPENDENT_CODE |   120 |   240 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

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

   2 - access("DEPENDENT_CODE"='1078754196')


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

Here you can see Index range scan occured and execution time dropped to  00:00:00.01 seconds.

No comments:

Post a Comment