今天在做SQL Tuning的时候遇到一个典型的example,立个Flag,梳理知识点,在这里也做个分享,就是我们在写SQL的时候如果对索引字段使用函数炒作,则导致该SQL不走索引扫描查询,导致SQL性能下降。
SQL如下:
SELECT NVL(A.USER_NAME_C, NVL(A.USER_NAME_E, A.USER_CODE)) USER_NAME,
A.TEL_NO,
A.FAX_NATION_CODE || A.FAX_AREA_CODE || A.FAX_LOCAL_NO FAX_NO
FROM AAA3010 A, AAA3009 B
WHERE A.CUST_SEQ_NO = B.CUST_SEQ_NO AND CUST_TYPE = 1
AND DECODE(A.USER_CODE, 'CN19000125', 1, 'WHL', 1, 2) = 1;
该SQL对A.USER_CODE字段使用DECODE函数,所以导致没有走Index扫描查询,如下该SQL的执行计划:
Execution Plan
----------------------------------------------------------
Plan hash value: 2797870618
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 920 | 56 (2)| 00:00:01 |
| 1 | NESTED LOOPS | | 20 | 920 | 56 (2)| 00:00:01 |
| 2 | NESTED LOOPS | | 62 | 920 | 56 (2)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | AAA3010 | 62 | 2356 | 43 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | AAA3009_PK | 1 | | 1 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID| AAA3009 | 1 | 8 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
看该Table结构,发现该Table的组合Index字段是(USER_CODE, CUST_SEQ_NO),如下图:
但是SQL对Index栏位调用Decode函数导致查询无法走索引扫描,通常如果有可替代方案则最好是不要对Index栏位使用函数,这里我们可以对该SQL拿掉Decode函数,改用In的方式查询,则查询时走索引扫描,提高SQL性能。
即修改成如下:
DECODE(A.USER_CODE, 'CN19000125', 1, 'WHL', 1, 2) = 1; AND A.USER_CODE in('CN19000125','WHL');
则走Index扫描查询,如下该SQL的执行计划:
Execution Plan
----------------------------------------------------------
Plan hash value: 3932238443
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 92 | 2 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 2 | 92 | 2 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 2 | 92 | 2 (0)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| AAA3010 | 2 | 76 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | AAA3010_PK | 2 | | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | AAA3009_PK | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | AAA3009 | 1 | 8 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------