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。