ABAP程序效率優(yōu)化系列文章歷史
ABAP程序效率優(yōu)化系列之①——業(yè)務(wù)層面的優(yōu)化
寫在前面
1招盲、讀取數(shù)據(jù)庫優(yōu)化的這兩篇(上一篇和這一篇),對于HANA來說意義不大,一直在HANA數(shù)據(jù)庫上進行開發(fā)的朋友請忽略
2、本文中的所有例子都是ORACLE數(shù)據(jù)庫上的
3、大家在測試時,如果遇到與我不同的測試結(jié)果,也屬于正撑罨恚現(xiàn)象
4、我的目的是讓大家通過ST05看到SQL的執(zhí)行軌跡菇肃,了解它大概是怎么回事地粪。然后通過HINTS的方式,在執(zhí)行軌跡不符合我們的預(yù)期時琐谤,進行適當(dāng)?shù)母深A(yù)
5蟆技、性能優(yōu)化在運維項目上的作用尤其大,建設(shè)項目的數(shù)據(jù)量小斗忌,復(fù)雜度相對低质礼,難以體會到性能的瓶頸。
初識ST05
首先织阳,我們在一個REPORT程序中編寫一段代碼:
然后打開ST05
接下來按以下步驟操作:
1眶蕉、Activate Trace
2、執(zhí)行REPORT程序
3唧躲、Deactivate Trace
4造挽、Display Trace,然后點執(zhí)行弄痹,可以得到如下的界面
?這個界面展示了SQL的執(zhí)行軌跡:
第二列饭入,是每一條SQL的執(zhí)行時間;
對象名列肛真,是對應(yīng)的表或視圖谐丢;
最后一列,是相應(yīng)的SQL語句蚓让。
初識執(zhí)行計劃
選中上圖中表AFPO OPEN操作的行乾忱,點擊工具欄上的”Explain”按鈕(F9),可以得到SQL的執(zhí)行計劃凭疮。
其中1、2串述、3為SQL執(zhí)行時的執(zhí)行順序执解。
步驟1中的AFPO~2,代表的是AFPO的索引2,該索引包括客戶端和PROJN兩個字段衰腌。
點擊1下面的Access Predicates新蟆,可以看到
即,第一步訪問AFPO表時右蕊,用的就是AFPO~2這個索引琼稻。
步驟2是根據(jù)步驟1得到的ROWID去AFPO獲取數(shù)據(jù),步驟3不用管它饶囚。
多個查詢條件的執(zhí)行計劃
換一段代碼
(在MSEG表中對BUDAT_MKPF新建了索引帕翻,索引名是Z05)
在我目前的項目上,這個SQL在開發(fā)機上執(zhí)行的很快萝风,到了生產(chǎn)機卻執(zhí)行的異常慢嘀掸。通過ST05監(jiān)測其執(zhí)行軌跡,發(fā)現(xiàn)結(jié)果如下:
在開發(fā)機上规惰,第一步是先根據(jù)budat_mkpf?Access睬塌,再根據(jù)werks和bwart?filter
在生產(chǎn)機上,第一步是先根據(jù)werks和bwart?Access歇万,再根據(jù)budat_mkpf?filter
要解決這個問題并不麻煩揩晴,只需要通過HINTS人工指定索引即可(上一期也提到了),即:
%_HINTS ORACLE ‘INDEX(MSEG “MSEG~Z05”)’贪磺。
(第一個MSEG可以不加引號)
至于生產(chǎn)機為什么和開發(fā)機是不一樣的SQL執(zhí)行計劃硫兰,這個我也不清楚。
據(jù)BASIS解釋說缘挽,是ORACLE的統(tǒng)計分析的結(jié)果瞄崇,導(dǎo)致了這樣的SQL執(zhí)行計劃。
ORACLE認(rèn)為它是最優(yōu)的壕曼,但在執(zhí)行時不一定總是最優(yōu)的苏研。
這時候就需要我們的人工干預(yù),以快速解決這樣的性能問題腮郊。
(一般情況下摹蘑,ORACLE的自動優(yōu)化都是沒太大問題的,但我在這里想說的是轧飞,我們要掌握一個快速解決處理的辦法衅鹿,以備不時之需)
表關(guān)聯(lián)的執(zhí)行計劃
代碼如下
執(zhí)行計劃如下
可以看到,多個表關(guān)聯(lián)時过咬,在圖片最上面的SQL STATEMENT中出現(xiàn)了T_00大渤、T_01,它們是參與JOIN的表的別名掸绞。
因此泵三,在表關(guān)聯(lián)時,指定索引的方式與只查詢一個表時略有不同,格式如下:
%_HINTS ORACLE ‘INDEX(T_00 “MSEG~OIB”)’
進一步分析
在此例中烫幕,大家也可以看到:
第一步俺抽,執(zhí)行的是MSEG~Z11的索引(自建的索引),這個索引包含的內(nèi)容是工廠和移動類型较曼;
第二步磷斧,是按客戶端過濾數(shù)據(jù);
第三步捷犹,執(zhí)行的是MKPF~0這個索引(~0是一個表的主鍵索引)弛饭,它包含的內(nèi)容是MKPF的主鍵字段,因為MSEG和MKPF進行了關(guān)聯(lián)伏恐;
第四步孩哑,是按MKPF的BUDAT過濾數(shù)據(jù)。
(這是我在我的開發(fā)系統(tǒng)的測試結(jié)果翠桦,大家也可以自己測一下這個代碼横蜒,應(yīng)該有很多人跟我是一樣的測試結(jié)果)
我們可以想象,如果數(shù)據(jù)很多的話销凑,我們是根據(jù)工廠和261做第一步更快丛晌,還是根據(jù)一個月的日期做第一步更快?肯定是后者岸酚住澎蛛!
那怎么辦呢?按照上面的方式指定索引嗎蜕窿?加上代碼
%_HINTS ORACLE 'INDEX("T_01" "MKPF~BUD")'
然后試試谋逻,結(jié)果如下:
第一步、第二步?jīng)]有變化桐经,第三步變了毁兆。
這并沒有達到預(yù)期的希望先ACCESS表MKPF的效果。
那我們把MKPF和MSEG關(guān)聯(lián)的順序顛倒一下可以嗎阴挣?你試過之后發(fā)現(xiàn)依然不行气堕。
怎么辦呢?ORACLE為什么不按我希望的順序執(zhí)行呢畔咧?
于是我開始翻資料茎芭,查找“ORACLE指定查詢順序”的關(guān)鍵字,沒找到原因誓沸,卻最終得到了以下的處理辦法:
?我把MKPF寫在MSEG之前梅桩,并且指定HINTS ordered,使SQL執(zhí)行計劃按表出現(xiàn)的順序執(zhí)行拜隧。
接下來是它的執(zhí)行計劃分析:
OKK薨佟煮寡!這太棒了!犀呼!
這就是我們想要的結(jié)果了!薇组!
案例與實際應(yīng)用
下面這兩個案例外臂,都是我在運維項目上遇到的實際案例。
案例1
SQL語句如下
SELECT
afpo~projn
aufk~auart
afko~aufpl
prps~post1
FROM afpo
INNER JOIN aufk ON aufk~aufnr = afpo~aufnr
INNER JOIN afko ON afko~aufnr = aufk~aufnr
INNER JOIN prps ON prps~pspnr = afpo~projn
WHERE afpo~prps IN (....).
IN的內(nèi)容較小時律胀,執(zhí)行沒有問題宋光,但是超過100條時,ST05的執(zhí)行軌跡如下:
第一步是PRPS的ACCESS
第四步是AUFK的ACCESS?FULL(全表掃描)炭菌,非常耗時
第五步才是AFPO的Z03索引
(Z03是我這里PROJN的索引罪佳,系統(tǒng)中有標(biāo)準(zhǔn)的AFPO~2索引,我也不清楚為什么之前的顧問建了個多余的索引)
(大家如果寫同樣的程序黑低,可能不會遇到跟我同樣的問題)
這個SQL的執(zhí)行速度超慢赘艳,大約5-10分鐘。
我一個表一個表的手動查詢克握,都用不了2分鐘的啊蕾管。
分析一下,這個很明顯就是ORACLE自動確定的執(zhí)行順序出了問題(至于怎么)菩暗,所以我就在后面加了ordered的hints掰曾,之后不到2秒鐘,結(jié)果就出來了停团。
案例2
代碼如下
其中GT_ALV中只有一條記錄旷坦,根據(jù)其記錄在PRPS可以找到18條數(shù)據(jù),進而在AFVC中找到4條數(shù)據(jù)佑稠,最后根據(jù)AFVC的4條數(shù)據(jù)查詢COSP的內(nèi)容秒梅。
然而,它在生產(chǎn)系統(tǒng)的執(zhí)行軌跡是這樣的:
它按照順序PRPS-AFVC-COSP的順序執(zhí)行讶坯,但是COSP時卻意外的ACCESS FULL番电,看看嚇人的CPU-Costs和IO-Costs吧,有沒有要解決掉的沖動辆琅?
動手吧漱办,因為它同樣很簡單,指定COSP的索引COSP~1即可(INDEX(T_02 "COSP~1"))婉烟,COSP~1的第一個字段就是OBJNR娩井。
結(jié)果當(dāng)然也是很快的,一瞬間似袁,就查詢出來了洞辣。
寫在最后
利用index和ordered這兩個hints咐刨,可能還是無法完全解決我們遇到的問題。除此之外扬霜,hints家族中還有leading(指定首先訪問的表)定鸟、use_nl(nested loop的join方式)、use_hash(hash join的方式)等著瓶。
對于oracle联予,我懂的也不多,這幾個hints怎么用材原,大家還是自己上網(wǎng)了解一下吧沸久,網(wǎng)上的Oracle大神數(shù)不勝數(shù),隨便支點招就夠我們abaper用的了余蟹。
IOS/ANDROID用戶打賞——贊賞碼