摘要 目前采用SAP產(chǎn)品的通常為大型企業(yè),這些企業(yè)的數(shù)據(jù)特點(diǎn)體現(xiàn)為數(shù)據(jù)表多、數(shù)據(jù)量大、數(shù)據(jù)關(guān)系復(fù)雜。有關(guān)技術(shù)人員在二次開發(fā)工作中,都無法避免超大數(shù)據(jù)量的運(yùn)算,而硬件升級的辦法(比如采用SAP HANA系統(tǒng))則以投資大、周期長困擾著相關(guān)企業(yè)。本文將以某單位的異常訂單監(jiān)控程序為例,介紹直接通過軟件優(yōu)化,高速處理超大數(shù)據(jù)量信息的方法。
【關(guān)鍵詞】SAP ABAP算法優(yōu)化 大批量數(shù)據(jù)處理
1 引言
在信息化系統(tǒng)的深化應(yīng)用過程中,許多企業(yè)都面臨著如何快速處理海量數(shù)據(jù)的問題。以某單位的SAP ERP為例,其財務(wù)數(shù)據(jù)量以億記,物料、工藝數(shù)據(jù)量以千萬記,其它業(yè)務(wù)數(shù)據(jù)量也多以百萬記,如果無法快速地對這些數(shù)據(jù)進(jìn)行計算,這些海量數(shù)據(jù)中蘊(yùn)藏的價值就得不到有效地利用。
SAP公司提供的HANA系統(tǒng)或者其它實施公司的硬件升級方案,效果雖然明顯,但成本通常在千萬以上、實施周期以年計。故本文將以實例介紹低成本、短周期,依靠軟件優(yōu)化方式快速處理大批量數(shù)據(jù)的方法。
2 背景
2.1 傳統(tǒng)處理大批量數(shù)據(jù)的方法及其局限性
第一種常用處理大批量數(shù)據(jù)的方法是中間表方式。以財務(wù)月結(jié)為例,如果直接利用原始憑證信息生成月結(jié)表速度將非常緩慢。所以最好的辦法是,每月關(guān)賬時運(yùn)行后臺程序(可參考本人論文《利用SAP PORTAL平臺實現(xiàn)門禁信息查詢》第二章),將計算結(jié)果存入中間表,等到需要月結(jié)或年度報表時,直接利用中間表生成報表。這種方法用戶體驗好,缺點(diǎn)是時效性不強(qiáng)。
第二種常用處理大批量數(shù)據(jù)的方法是分批處理。以人力資源的組織結(jié)構(gòu)為例,大型企業(yè)的組織節(jié)點(diǎn)(SAP中將人員也視為組織節(jié)點(diǎn),以便于生成組織樹)達(dá)到幾十萬個,生成組織結(jié)構(gòu)圖極其緩慢。于是我們將每個節(jié)點(diǎn)及其以下三層算作一個“批次”,首先僅展開根節(jié)點(diǎn)及其以下三層,如果用戶雙擊某個節(jié)點(diǎn),再展開這個節(jié)點(diǎn)下面三層,以此類推。這是因為用戶真正要查看的組織和人員往往只占所有組織節(jié)點(diǎn)的很小一部分,大量數(shù)據(jù)對于用戶而言是無用的,排除無用數(shù)據(jù)的計算可以大幅增加數(shù)據(jù)處理速度。
2.2 異常訂單監(jiān)控任務(wù)的特點(diǎn)
某單位的異常訂單監(jiān)控任務(wù),具有四個特點(diǎn):涉及數(shù)據(jù)龐大、計算邏輯復(fù)雜、及時性要求高、無用數(shù)據(jù)少。這決定了傳統(tǒng)的中間表方法和分批計算的方法此處并不適用,只能另辟蹊徑。
3 SQL語言優(yōu)化方法
3.1 合理減少連接( JOIN)數(shù)據(jù)表的數(shù)量
如果將所有表格進(jìn)行連接( JOIN),形成的笛卡爾積最高可達(dá)到10^56次方。要加快取數(shù)速度,首先要減少連接表的數(shù)量,一些跟輸入條件沒有直接關(guān)系的數(shù)據(jù)表,最好排除出主SQL語句,然后另行處理。
本程序的輸入條件包括工廠、訂單類型、分廠、生產(chǎn)訂單、物料號、WBS號、工作中心、交貨時間,與之有關(guān)的表格為AFKO、AFPO、AUFK、AFVC、CRHD、PRPS,
故這6個表格需要在主SQL語句中互相連接。此時主SQL的數(shù)據(jù)明顯減少。而其它數(shù)據(jù)表則另行用單獨(dú)的SQL寫入各自對應(yīng)的臨時內(nèi)表,再通過READ TABLE方法填入主內(nèi)表(若內(nèi)表鍵值己排序,按鍵值二分法查找速度會更快)。
另外,如果我們只想用READ TABLE判斷某行數(shù)據(jù)是否存在,而不需要讀取該行數(shù)據(jù),可以在READ TABLE最后增加TRANSPORTING NO FIELDS關(guān)鍵字,進(jìn)行加速。
對于那些數(shù)據(jù)量大的表(如AFVV含2100多萬條數(shù)據(jù),MAKT含200多萬條數(shù)據(jù)),直接讀取不僅慢而且占用大量內(nèi)存空間,故需要索引表的協(xié)助。如圖1,我們用索引表ITAB OUTPUT1復(fù)制了主內(nèi)表ITABOUTPUT的數(shù)據(jù)(含有我們需要的數(shù)據(jù)的鍵值),按工藝路線號( AUFPL)排序,再刪除重復(fù)的工藝路線號,就可以得到工藝路線號的索引表。
如圖2,我們用索引表ITAB OUTPUT1作為條件,快速從AFVV表中讀取需要的工序數(shù)據(jù),而主內(nèi)表則可在循環(huán)中通過READTABLE快速從臨時內(nèi)表ITAB AFVV中填補(bǔ)上每行的工序數(shù)據(jù)。使用索引表需要注意兩點(diǎn)
(1)索引表為空時,取數(shù)速度反而比普通SQL更慢,所以應(yīng)避免索引表為空;
(2)索引表做“等于”比較時速度很快,但是做“不等于”比較時,會讓數(shù)據(jù)庫各行遍歷比較索引表各行,非常耗時,所以應(yīng)避免“不等于”比較。
另外,出于節(jié)省內(nèi)存空間的考慮,使用完的索引表和臨時內(nèi)表應(yīng)該及時清空。
3.2 強(qiáng)化篩選條件
SQL對數(shù)據(jù)的篩選有兩處,一處為連接( JOIN)后面ON的條件,一處為WHERE條件。前者會首先執(zhí)行,可以有效避免數(shù)據(jù)表做笛卡爾乘積,但它們的邏輯比較簡單,通常是鍵值的計算,很難把邏輯做強(qiáng)。我們通常強(qiáng)化的是后面的WHERE條件。
若僅僅以輸入條件(見2.1節(jié))作為篩選條件,其單次取數(shù)耗時依然在5分鐘以上。在東電的業(yè)務(wù)中,工作中心數(shù)據(jù)、物料數(shù)據(jù)均跟工廠編號存在邏輯關(guān)聯(lián)(例如工作中心編碼和分廠編碼存在對應(yīng)關(guān)系),同時工序控制碼、訂單類別、項目編號也可以增加約束條件(例如外協(xié)工序和說明工序,就不用考慮報工的問題),故我們可通過增強(qiáng)篩選條件的方式減少不必要的取數(shù)工作。
如圖3,盡管輸入條件只有8個,但我們底層代碼的篩選條件卻多達(dá)15個,將SQL取數(shù)時間從5分鐘以上縮減到3秒以內(nèi)。
注意:
(1)篩選條件中應(yīng)避免通配符的使用;
(2)各企業(yè)數(shù)據(jù)規(guī)范不同,故增強(qiáng)篩選條件的方式也會不同,需要根據(jù)實際情況進(jìn)行選擇。
3.3 使用游標(biāo)( CURSOR)
SQL語言取數(shù)時會將數(shù)據(jù)臨時存到內(nèi)存的結(jié)果集,而游標(biāo)就是指向結(jié)果集的指針。本身逐行操作是慢于普通SQL的,但是由于SAP的內(nèi)存管理機(jī)制,特定情況下游標(biāo)反而體現(xiàn)出性能優(yōu)勢。
一旦物理內(nèi)存不足,SAP系統(tǒng)會向SWAP請求擴(kuò)展空間,此時運(yùn)算會變得很慢。如果連擴(kuò)展空間都不足,則會報內(nèi)存錯誤,甚至無法正常取數(shù)。游標(biāo)在這時不僅能保證取數(shù)正常,還快于一般的SQL。如圖4所示。
注意:
(1)只有數(shù)據(jù)量特別大而篩選條件較少時,顯式游標(biāo)的性能優(yōu)勢才能體現(xiàn)出來;
(2) -般情況應(yīng)避免使用游標(biāo);
(3)游標(biāo)使用后需要關(guān)閉,否則會內(nèi)存泄漏。
3.4 使用提示( HINTS)
ABAP語言也支持在SQL中使用提示(HINTS),我們可以通過提示設(shè)定檢索數(shù)據(jù)表的索引、連接順序、索引表、SQL執(zhí)行方式等工作。
通過事務(wù)代碼sell表找到需要優(yōu)化的數(shù)據(jù)表,通過轉(zhuǎn)到.>索引即可創(chuàng)建或管理該數(shù)據(jù)表的提示索引。圖5例子中,我們?yōu)榱硕壋杀竞怂阍贑SKS表增加了Z01索引,在SQL語句的FROM后增加“%HINTSORACLE'INDEX(”CSKS””CSKS~Z01”)”,就可以用Z01中的字段代替鍵值進(jìn)行檢索,從而加速。
注意:索引的設(shè)計非常依賴各個業(yè)務(wù)單位的數(shù)據(jù)規(guī)范和技術(shù)人員的個人經(jīng)驗,所以一般不推薦使用。
4 針對邏輯代碼的優(yōu)化
4.1 避免遞歸和多重循環(huán)
在對SQL語言進(jìn)行優(yōu)化后,我們獲得的主內(nèi)表數(shù)據(jù)從25萬行縮減到了10萬行。雖然主內(nèi)表的行數(shù)明顯減少,但是要快速處理這些數(shù)據(jù),依然不得不對邏輯代碼進(jìn)行優(yōu)化。傳統(tǒng)上軟件工程師用遞歸或多重循環(huán)的方式處理聯(lián)合訂單,我根據(jù)業(yè)務(wù)邏輯設(shè)計了用標(biāo)志位代替遞歸和多重循環(huán)的算法。
我們將訂單狀態(tài)和工序狀態(tài),抽象為了4個類型,當(dāng)我們按訂單號從大到小排列時,循環(huán)就會按照從上層到下層的順序遍歷這些訂單行,并標(biāo)記其訂單狀態(tài)、工序狀態(tài)、子訂單狀態(tài)、子工序狀態(tài)。而我又將錯誤類型抽象為5個類型,并列出了狀態(tài)與錯誤類型的對應(yīng)關(guān)系。
根據(jù)狀態(tài)與錯誤的對照關(guān)系,我們可以有效判斷各行是否出錯,出錯類型是什么。我們對數(shù)據(jù)的判斷和分類,只需要一次循環(huán)加一些READ TABLE操作即可完成。使用標(biāo)志位還有兩個優(yōu)點(diǎn):
(1)編號有擴(kuò)展性,可適應(yīng)追加需求;
(2)當(dāng)標(biāo)志位滿足不進(jìn)行后續(xù)計算的條件時,就可以直接省略后續(xù)計算。
根據(jù)不同的業(yè)務(wù)邏輯,工程師可以采用不同方式回避遞歸和多重循環(huán)的存在。標(biāo)志位這種方式與控制工程的原理類似,是適用性比較廣的方式。
4.2 使用字段符號( FIELD-SYMBOLS)
ABAP循環(huán)默認(rèn)使用工作區(qū)指向循環(huán)的各行,工作區(qū)是單獨(dú)開辟的內(nèi)存地址。如果我們修改各行數(shù)據(jù),需要先修改工作區(qū),然后再通過邏輯條件尋址,再修改內(nèi)表所處的內(nèi)存地址,一旦內(nèi)表過大,這種計算方式就會非常緩慢。字段符號(FIELD-SYMBOLS)是直接指向內(nèi)表各行的指針,允許我們直接修改內(nèi)表以節(jié)省尋址時間。如圖6所示。
4.3 謹(jǐn)慎使用刪除和修改操作
ABAP中對內(nèi)表進(jìn)行刪除(DELETE)和修改( MODIFY)操作,使用WHERE語句作為判定條件,其原理是遍歷內(nèi)表,找到符合條件的行,再進(jìn)行操作。因為需要遍歷內(nèi)表,在內(nèi)表特別龐大時這種操作極其緩慢。對于這類操作,第一是盡量不使用,第二是必須使用時盡量在循環(huán)外使用,第三是必須在循環(huán)內(nèi)使用時應(yīng)使用索引(INDEX)而不是判定條件。
對于刪除操作,可以先在循環(huán)時將要刪除的行做好標(biāo)記,然后再在循環(huán)外統(tǒng)一刪除。在圖7中,我就是在循環(huán)外統(tǒng)一刪除了DESCRIPT__ NO為-l(即需要刪除的標(biāo)記)的所有行。這樣也便于計算行序,因為ABAP中每次刪除操作后,行序都會重新置O,不利于使用索引進(jìn)行定位。對于修改操作來說,可使用字段符號(見4 2節(jié))避免大部分有關(guān)操作。
對于不得不在循環(huán)中使用的刪除或者修改操作,需要使用索引。在圖8中,我們利用INDEX關(guān)鍵字,直接用索引找到內(nèi)表的對應(yīng)行進(jìn)行修改,避免了復(fù)雜的匹配運(yùn)算。另外,我們可以利用TRANSPORTING語句限制要修改的數(shù)據(jù)有哪些,也可以加快計算速度。
4.4 字符串計算優(yōu)化
訂單狀態(tài)和工序狀態(tài),本質(zhì)是多個狀態(tài)構(gòu)成的字符串,所以這類程序必然涉及到字符串計算。合理使用&&計算代替拼接( CONCATENATE)計算,使用CS、NS等基礎(chǔ)計算代替分割( SPLIT)和尋找(FIND)計算,都可以有效地進(jìn)行計算加速。
比如,當(dāng)我判斷訂單狀態(tài)是否包含是否為交貨(DLV)時,需要判定訂單狀態(tài)字符串是否包含“DLV”這個狀態(tài)。傳統(tǒng)做法是用空格分割字符串再分別比較,或者遍歷字符串尋找“DLV”狀態(tài)。而優(yōu)化算法的偽代碼可寫成“IFSTTXT CS 'DLW AND STTXT NS 'PDLW'(即當(dāng)前狀態(tài)文本包含DLV字符串但不含PDLV字符串),速度會比分割比較或者遍歷尋找快得多。
需要注意的是,ABAP語言在進(jìn)行字符和數(shù)字之間的計算時,會在底層進(jìn)行格式轉(zhuǎn)換計算,速度是比較慢的。故設(shè)計程序時最好避免字符和數(shù)字間的運(yùn)算。
5 輔助工具
如圖9所示,若程序員無法憑借經(jīng)驗判斷程序哪個節(jié)點(diǎn)比較耗時,則可借助SAP自帶的程序運(yùn)行時間分析工具(事務(wù)代碼se30),該工具可以協(xié)助程序員看到各個節(jié)點(diǎn)的耗時和耗時比重;若程序員希望看到數(shù)據(jù)庫操作的細(xì)節(jié)性能,則可以使用事務(wù)代碼ST05追溯SQL的運(yùn)行軌跡。通過對程序各部分執(zhí)行效率的分析,我們就可以采取有針對性的優(yōu)化。
此外,ABAP語言提供了“GET RUNTIME FIELD tl”(tl為程序員定義的整型變量)這種語句,該語句可獲取程序當(dāng)前時間(時間單位為微秒)。程序員可以在不同位置安插該語句,然后通過獲取的時間差值來評估程序的效率。
6 結(jié)語
異常訂單監(jiān)控程序在優(yōu)化前運(yùn)行時間超過36分鐘,而在優(yōu)化后運(yùn)行時間壓縮到5分鐘左右,對于用戶體驗提升巨大。技術(shù)人員可以根據(jù)情況選擇本文的算法優(yōu)化或2.1節(jié)介紹的方法高速處理大批量數(shù)據(jù)。在提升系統(tǒng)效率、挖掘數(shù)據(jù)資源方面,軟件優(yōu)化的方法跟硬件升級的方法一樣,都是可行且有效的。
參考文獻(xiàn)
[1]兔寶.SAP ABAP游標(biāo)的使用(示例)[OL] http://blog. csdn. net/szlaptop/article/details/8565285.
[2] Twilight.ABAP MODIFY語句如何高性能修改內(nèi)表中多條數(shù)據(jù)[OL].http://bbs.sapclub. cc/thread-490-1-1. html.
[3]王建文.利用SAP PORTAL平臺實現(xiàn)門禁信息查詢[J].中國管理信息化,2016,19 (01).