一次fast full scan的調優

1.閒着無聊在客戶一套較爲重要的系統中提取了一個4天的AWR,發現下面這條SQL產生最多的物理讀,四天運行了159次。平均每次物理讀1G左右。SQL運行時間三分鐘左右。ide

SQL:性能

SELECT DECODE(B.DH, 'MAIN', :1, B.DH) DH, COUNT(DISTINCT(A.PROCESSID)) VALUE,orm

B.MC COMPANYNAME FROM FMIS3000.WF_ACTIVITIES A, (SELECT DH, MC FROM FMIS3000.XTDW WHERE 1=1 )排序

B WHERE A.ACTTYPE = 1 AND TRIM(A.DH) = TRIM(B.DH) GROUP BY B.DH, B.MC;索引

2.我查看了執行計劃:ip

PLAN_TABLE_OUTPUTget

 

Plan hash value: 2953189885hash

 

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |it

 

| 0 | SELECT STATEMENT | | 191K| 18M| | 300K (1)| 01:10:12 |io

| 1 | SORT GROUP BY | | 191K| 18M| 4006M| 300K (1)| 01:10:12 |

|* 2 | HASH JOIN | | 37M| 3516M| | 45650 (1)| 00:10:40 |

| 3 | TABLE ACCESS FULL| XTDW | 528 | 18480 | | 4 (0)| 00:00:01 |

|* 4 | TABLE ACCESS FULL| WF_ACTIVITIES | 7054K| 430M| | 45478 (1)| 00:10:37 |

 

PLAN_TABLE_OUTPUT

 

Predicate Information (identified by operation id):

 

2 - access(TRIM("A"."DH")=TRIM("DH"))

4 - filter("A"."ACTTYPE"=1)

17 rows selected.

3.我注意到有兩個全表掃描,因而我查找執行這個SQL時 兩個表會返回的數據量

這是一個HASH鏈接 FMIS3000.XTDW 表爲驅動表,能夠看到他數據量不大,做爲驅動表仍是很合適的,走table access full,也比較合理。

SQL> select count(*) from FMIS3000.XTDW ;

COUNT(*)

 

530

4.這是被驅動表,數據量比較大。我發現這兒應是一個瓶頸。

SQL> select count(*) from FMIS3000.WF_ACTIVITIES where ACTTYPE=1;

COUNT(*)

 

12078901

5.這個查詢返回1.2KW數據,整個表有1.7KW數據。走全表掃描其實並無錯,可是我在想如何解決這個瓶頸

6.接着我返回去看SQL,發現我不須要掃描整個表的數據:

通過查詢這個表有26列,我能夠在須要的列上面建立索引。

create index id_tex on FMIS3000.WF_ACTIVITIES(ACTTYPE,TRIM(DH),PROCESSID);

在這兒我沒有考慮選擇性(由於不須要,並且選擇性確定奇差),我推測這樣,能夠走INDEX FAST FULL SCAN,且不用回表。將會有效提高效率。

創建索引前:

PLAN_TABLE_OUTPUT

 

SQL_ID 4n6ajf2fsm2x9, child number 0

 

SELECT DECODE(B.DH, 'MAIN','MAIN', B.DH) DH, COUNT(DISTINCT(A.PROCESSID)) VALUE, B.MC COMPANYNAME FROM

FMIS3000.WF_ACTIVITIES A, (SELECT DH, MC FROM FMIS3000.XTDW WHERE 1=1 ) B WHERE A.ACTTYPE = 1 AND

TRIM(A.DH) = TRIM(B.DH) GROUP BY B.DH, B.MC

Plan hash value: 2953189885

 

| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes |

 

| 1 | SORT GROUP BY | | 1 | 191K| 475 |00:02:51.39 | 285K| 423K| 138K|

|* 2 | HASH JOIN | | 1 | 37M| 12M|00:01:12.56 | 285K| 285K| 0 |

| 3 | TABLE ACCESS FULL| XTDW | 1 | 528 | 530 |00:00:00.02 | 10 | 8 | 0 |

|* 4 | TABLE ACCESS FULL| WF_ACTIVITIES | 1 | 7054K| 12M|00:00:48.38 | 285K| 285K| 0 |

 

Statistics

 

1082 recursive calls

71 db block gets

285137 consistent gets

311743 physical reads

0 redo size

2208 bytes sent via SQL*Net to client

514 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

1 sorts (disk)

30 rows processed

創建索引後:

PLAN_TABLE_OUTPUT

 

SQL_ID g5pavm81dbpdt, child number 0

 

SELECT DECODE(B.DH, 'MAIN', 'MAIN', B.DH) DH, COUNT(DISTINCT(A.PROCESSID)) VALUE, B.MC COMPANYNAME

FROM FMIS3000.WF_ACTIVITIES A, (SELECT DH, MC FROM FMIS3000.XTDW WHERE 1=1 ) B WHERE A.ACTTYPE = 1

AND TRIM(A.DH) = TRIM(B.DH) GROUP BY B.DH, B.MC

Plan hash value: 513252325

 

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

 

| 0 | SELECT STATEMENT | | 191K| 18M| | 341K (2)| 01:08:17 |

| 1 | SORT GROUP BY | | 191K| 18M| 4062M| 341K (2)| 01:08:17 |

|* 2 | HASH JOIN | | 37M| 3516M| | 39892 (2)| 00:07:59 |

| 3 | TABLE ACCESS FULL | XTDW | 528 | 18480 | | 4 (0)| 00:00:01 |

|* 4 | INDEX FAST FULL SCAN| TE_DX | 7054K| 430M| | 39524 (2)| 00:07:55 |

 

Statistics

 

1074 recursive calls

51 db block gets

179736 consistent gets

124315 physical reads

0 redo size

2208 bytes sent via SQL*Net to client

514 bytes received via SQL*Net from client

3 SQL*Net roundtrips to/from client

0 sorts (memory)

1 sorts (disk)

30 rows processed

這個執行計劃是真實的

能夠很明顯的看到,無論是邏輯讀和物理讀都少了一倍左右。(我在執行前都flush了share pool和buffer cache)

創建索引以後 CBO自動選擇了INDEX FAST FULL SCAN ,並且確實沒有回表。和預估的結果同樣。

總的執行時間減小了一倍,在掃描WF_ACTIVITIES表階段 時間從48秒減小到了8秒。性能提高了6倍。

可是這個SQL還有個瓶頸是SORT GROUP BY 也就是DISTINCT排序致使的。 我也試驗了,若是不要distinct,執行時間還能夠減小30多秒,這個和業務相關了,就沒有太大辦法,並且被驅動表返回結果1.2KW行,hash不可能不消耗時間,這個確實沒辦法。若是知道業務或許能夠改寫SQL。

相關文章
相關標籤/搜索