Thursday, May 1, 2008

Eliminate FULL TABLE ACCESS

In SQL quarry tuning one of the major goals is to eliminate FULL TABLE ACCESS. Using index we can achieve the goal. let see how it can be achieve

Suppose we have the following table

SQL> desc emp;

Name Type
---------- ----------------------------
EMPNO NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

Now enable the autotrace option to see sql quarry execution plan.

SQL> set autotrace on;
SQL>
SQL> select * from emp;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10

14 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 1218 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMP | 14 | 1218 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------

Update some rows for experimant purpose.

SQL> update emp set sal=500 where sal<2000;
8 row updated.
SQL> commit;
Commit complete.

SQL> create unique index empno_emp on emp(empno);
Index created.
SQL> select empno from emp where empno>0;

EMPNO
----------
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

14 rows selected.

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

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

The EMPNO_EMP index is not used because we access all 14 row.


SQL> select empno from emp where empno<7700;

EMPNO
----------
7369
7499
7521
7566
7654
7698

6 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 2992108249
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 78 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| EMPNO_EMP | 6 | 78 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------

Here you can see the index is used because we access a portion of 14 rows.

SQL> select empno from emp where sal=500;

EMPNO
----------
7369
7499
7521
7654
7844
7876
7900
7934

8 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 208 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 8 | 208 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------

Again you can see the index is not used because indexed column empno in not prasent in the "WHERE" close.


To ellimenate full table scane of previous sql quarry create an index on sal column which is in the "WHERE" close.

SQL> create index sal_emp on emp(sal);

Index created.

SQL> select empno from emp where sal=500;

EMPNO
----------
7369
7499
7521
7654
7844
7876
7900
7934

8 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 216044341
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 208 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 8 | 208 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SAL_EMP | 8 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------

See ! we r abole to elliminate the full table scan..


Learning: If you have an index and the indexed column is not present in "Where" close the index will not be used.

Let go to our second experimant. for this drop the previously build indexs

SQL> drop index empno_emp;

Index dropped.

SQL> drop index sal_emp;

Index dropped.

Create a composite index

SQL> create index EMPNO_SAL_EMP on emp(empno,sal);
Index created.


SQL> select empno from emp where empno<7900;

EMPNO
----------
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876

11 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 615958546
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 143 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| EMPNO_SAL_EMP | 11 | 143 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------

SQL> select empno from emp where sal=500;

EMPNO
----------
7369
7499
7521
7654
7844
7876
7900
7934

8 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1761287244
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 208 | 1 (0)| 00:00:01 |
|* 1 | INDEX FULL SCAN | EMPNO_SAL_EMP | 8 | 208 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------

See EMPNO_SAL_EMP index experienced FULL SCAN because the quarry has sal (right part of index) in "WHERE" close.


SQL> select ename,empno,deptno from emp where deptno=30 and sal=500;

ENAME EMPNO DEPTNO
---------- ---------- ----------
ALLEN 7499 30
WARD 7521 30
MARTIN 7654 30
TURNER 7844 30
JAMES 7900 30


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 230 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 5 | 230 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------

Again an interesting thing .. now the table experienced FULL SCAN because select close has non indexed column and sal (right part of index) in "WHERE" close.


SQL> select ename,deptno from emp where empno<7700;

ENAME DEPTNO
---------- ----------
SMITH 20
ALLEN 30
WARD 30
JONES 20
MARTIN 30
BLAKE 30

6 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 1330938245
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 198 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 6 | 198 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMPNO_SAL_EMP | 6 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

This time empno (left part of the index) prasent in the "WHERE"close.

Learning : if you have composite index, make sure all/most of columns are present in "where" close in same order (suppose you have 3 column index and 2 &3 are in where close, the index is not used, you must have 1,2,3 or 1,2 or 1,3 colume in "WHERE" close)

No comments: