最佳化ALV報表,最主要就是最佳化取數邏輯和資料庫查詢。因為幾乎在所有的程式中都會用到資料庫查詢,所以這篇文章的內容也不僅局限於SAP、ABAP程式,雖然ABAP有其特殊之處。
最佳化的時候我遵從以下幾個原則:
1.把資料庫連接視為一種極其珍貴的資源,大量的資料庫操作會增加網路負載,增加程式的運行、等待時間,降低程式效能。因此有以下的注意事項:
(1)因此資料庫操作能少則少,嚴禁在迴圈中寫SQL語句對資料庫進行操作;
(2)應該將資料讀取到記憶體中,對記憶體中的資料進行操作,如排序和運算等,而不是直接對資料庫表進行;
2.多表串連查詢時,串連的表的數量不超過2-3張。當表的數量過多、資料量大時,會極大程度影響效能。應該先將資料讀取到內表(類似於數組)中,使用FOR ALL ENTRIES IN 來和其餘需要串連的表進行關聯。且簇表無法串連,只能使用FOR ALL ENTRIES IN的方法。 雖然我看到有開發規範說儘可能只串連1張表,但是實際的業務需求中經常只是取其他表的1、2個欄位,為了這1、2個欄位單獨建結構,然後用FOR ALL ENTRIES IN查詢實在是太麻煩,這裡把限制放寬到2-3張也算是為了方便和為了效能的折中考慮吧。
3.儘可能使用系統提供的方法,而不是自己實現。比如使用SQL的彙總函式進行統計、計算,而不是自己實現。
4.少迴圈。當資料量比較大時,多次迴圈會消耗大量的時間和效能。所以迴圈語句應該近可能少,盡量避免嵌套迴圈,儘可能將操作放在一次迴圈中進行。
5.使用一些高效的寫法(至少我認為是高效的:)),在編程和最佳化過程中不斷的參照了一些Performance Examples裡的一些寫法。主要是以下幾點:
(1)需要修改內表中的某行的某欄位值時,我選擇使用
FIELD-SYMBOLS(類似指標),LOOP ... ASSIGNING field-symbols和READ TABLE itab ASSIGNING field-symbols這樣的寫法,
而不是使用
LOOP ... INTO wa READ TABLE itab INTO wa 修改完後再MODIFY TABLE itab FROM wa;
(2)聲明的變數儘可能指明類型、長度;
(3)對於長度較長、長度可變的字串使用STRING類型替代C類型;:
當然難免有產生衝突的情況,比如:有時多次迴圈、嵌套迴圈不可避免,使用彙總函式進行統計需要額外的一次資料庫查詢等,這就需要具體情況具體分析,選擇一種折中、合適的方法。
一些最佳化執行個體:
1.使用了動態查詢條件,適用於查詢欄位相同,只是條件不同的情況,主要是減少了重複代碼,說不上能改善效能。
2.將兩次迴圈合并成一次迴圈進行
將原來的兩段迴圈:
合并成:
3.使用SELECT……ENDSELECT-LOOP
這個類似於常規SQL中的遊標,能每次對查詢結果中的單條資料進行處理和操作。這個一定程度上彌補了ABAP的OPEN-SQL無法對查詢欄位做運算和SELECT 常量的操作:例如select a+b from tab 和 select ‘常量’,但感覺上使用SELECT……ENDSELECT-LOOP會增加資料庫連接的佔用時間。
我使用SELECT……ENDSELECT-LOOP篩選出COSS~WTG004和COSP~WTG004相加為零的結果,將原來一次額外的LOOP寫到SELECT……ENDSELECT-LOOP中。
OPEN-SQL沒法SELECT常量,所以只能查詢後再手動修改,我將修改的一次額外迴圈也合并到SELECT……ENDSELECT-LOOP。
4.使用子查詢,這在ABAP效能執行個體中也提到過,當需要判斷是否存在時使用EXISTS加子查詢,而不要在SELECT……ENDSELECT-LOOP重新查詢是否存在,這樣相當於迴圈中執行SQL。
5.使用彙總函式,而不是自己實現統計功能,尤其是需要進行分組統計時。
6.在需要擷取內表長度的時候,用ABAP關鍵字DESCRIBE TABLE itab LINES length,而不是自己迴圈內表進行統計。
小結
看了公司發的開發規範,覺得有些地方和我自己的想法還是有些出入,比如當中要求:
在SELECT中盡量避免使用SUM,MAX,GROUP BY,HAVING,GORDER BY語句和如果要使用JOIN,則最多使用一次JOIN,即兩個表聯集查詢
如果本文中所說的有不對之處,歡迎提出建議和改進。
作為一個有專業水準的技術顧問,對自己的要求是不僅是要完成功能,而且要在完成功能的基礎上讓代碼最少最優,這才體現出專業水準和技術水平,我也不希望後人看到My Code的時候覺得這是一坨無可救藥的垃圾代碼。共勉~!