嵌套循環的效率問題

不少人說,上了HANA,效率再也不是問題。數據庫

可遇到大量數據處理的時候,SQL查詢的時間在優化到儘量低以後,ABAP處理時間卻居高不下。不合理的嵌套循環帶給CPU的負擔,豈是HANA所能解決的?服務器

因此,把報表查詢太慢歸咎於數據庫響應時間太長,一味的依賴HANA去解決報表問題,這種態度是要不得的!app

 

本文針對優化嵌套循環提供一些思路,但願能讓你的大批量數據處理,從20分鐘縮短到幾秒。測試

【完整測試代碼和測試結果見本文末尾】優化

 

案例:spa

內表TAB1——學號、姓名。3萬條。code

內表TAB2——學號、課程、成績。30萬條。blog

如今TAB1和TAB2已經獲得,且已經人工排序,且定義時是TYPE STANDARD TABLE OF的方式定義的,如今要求根據TAB1和TAB2計算得出每一個學生的成績總分。排序

注:爲方便敲代碼,本文中的全部內表均爲帶表頭的內表。索引

 

常見寫法:

LOOP AT TAB1.

  LOOP AT TAB2 WHERE 學號 = TAB1-學號.

    累加處理.

    APPEND ... TO 合併表. 

  ENDLOOP.

ENDLOOP.

這樣寫,20分鐘可能都出不來數據。

緣由分析:對於標準表(STANDARD TABLE),LOOP..WHERE..是對每一行都執行判斷的。這樣的寫法,其實是執行了3W*30W次循環。

 

爲了提升嵌套循環的效率,就要減小循環次數。這是根本的出發點!

 

優化方式1[推薦]:

把TAB2的定義方式改成SORTED TABLE.

LOOP AT TAB1.

  READ TABLE TAB2 WITH KEY 學號 = TAB1-學號 BINARY SEARCH TRANSPORTING NO FILEDS.

  LOOP AT TAB2 FROM SY-TABIX.

    IF TAB2-學號 <> TAB1-學號.

      EXIT.

    ENDIF.

    "其餘處理...

  ENDLOOP.

ENDLOOP.

 

緣由分析:

內層循環表已排序,首先根據內層循環表用二分法查找到指定學號的索引,而後從索引處開始循環,循環到學號與外層學號不一致時,退出內層循環,減小內層循環次數。

 

優化方式2:

更改TAB2爲排序表,代碼與常見代碼一致。

緣由分析:

對於排序表,LOOP..WHERE..比標準表的LOOP..WHERE..要快不少不少。

但對於此例,此方式的效率大約爲方式1的效率的一半(詳細測試時間的對比見本文末尾)。【不一樣的服務器或客戶端可能會致使差別,也可能第二種比第一種方式更快一些】

 

優化方式3:【須要彙總內層數據,且內層單次循環量很小時,推薦使用】

定義TAB3,包含學號和成績。

LOOP AT TAB2.

  TAB3-學號 = TAB2-學號.

  TAB3-成績 = TAB2-成績.

  COLLECT TAB3.

ENDLOOP.

SORT TAB3 BY 學號.

LOOP AT TAB1.

  READ TAB3 WITH KEY 學號 = TAB1-學號 BINARY SEARCH.

  "其餘處理

ENDLOOP.

 

緣由分析:

循環次數,TAB2,30W次;TAB1,3W次。一共33W次。

 

測試代碼:

REPORT ztest_abap_ll.

TYPES:
  BEGIN OF typ1,
    no TYPE i,
    name(10) TYPE c,
  END OF typ1,

  BEGIN OF typ2,
    no TYPE i,
    course(5) TYPE c,
    score TYPE i,
  END OF typ2,

  BEGIN OF typ3,
    name(10) TYPE c,
    score TYPE i,
  END OF typ3.

DATA:
  tab1 TYPE TABLE OF typ1 WITH HEADER LINE,
  tab2 TYPE SORTED TABLE OF typ2 WITH NON-UNIQUE KEY no WITH HEADER LINE,
  ctab2 TYPE TABLE OF typ2 WITH HEADER LINE,
  tab3 TYPE TABLE OF typ3 WITH HEADER LINE.
DATA: ts1 TYPE timestampl,
      ts2 TYPE timestampl,
      ts TYPE timestampl.

PARAMETERS: p_out TYPE i OBLIGATORY,
            p_in TYPE i OBLIGATORY.

INITIALIZATION.
  %_p_out_%_app_%-text = '外層循環條目數'.
  %_p_in_%_app_%-text = '內層循環條目數'.

START-OF-SELECTION.
  "構建內表
  DO p_out TIMES.
    tab1-no = sy-index.
    tab1-name = 'NAME' && sy-index.
    APPEND tab1.
  ENDDO.

  DO p_out TIMES.
    tab2-no = sy-index.
    DO p_in TIMES.
      tab2-course = 'C' && sy-index.
      tab2-score = 80.
      INSERT tab2 INTO TABLE tab2.
    ENDDO.
  ENDDO.

  WAIT UP TO 1 SECONDS.
  PERFORM frm_1.

  REFRESH: tab3.
  WAIT UP TO 1 SECONDS.
  PERFORM frm_2.

  REFRESH: tab3.
  WAIT UP TO 1 SECONDS.
  PERFORM frm_3.

*&第一種方式處理-----------------------------------------------*
FORM frm_1.
  GET TIME STAMP FIELD ts1.

  LOOP AT tab1.
    tab3-name = tab1-name.
    READ TABLE tab2 WITH KEY no = tab1-no BINARY SEARCH TRANSPORTING NO FIELDS.
    LOOP AT tab2 FROM sy-tabix.
      IF tab2-no <> tab1-no.
        EXIT.
      ENDIF.

      ADD tab2-score TO tab3-score.
    ENDLOOP.

    APPEND tab3.
    CLEAR tab3.
  ENDLOOP.

  GET TIME STAMP FIELD ts2.

  ts = ts2 - ts1.
  WRITE: ts.
ENDFORM.                                                    "frm_1
*&第二種方式處理-----------------------------------------------*
FORM frm_2.
  GET TIME STAMP FIELD ts1.

  LOOP AT tab1.
    tab3-name = tab1-name.
    LOOP AT tab2 WHERE no = tab1-no.
      ADD tab2-score TO tab3-score.
    ENDLOOP.
    APPEND tab3.
    CLEAR tab3.
  ENDLOOP.

  GET TIME STAMP FIELD ts2.

  ts = ts2 - ts1.
  WRITE: ts.
ENDFORM.                                                    "frm_2
*&第三種方式處理-----------------------------------------------*
FORM frm_3.
  GET TIME STAMP FIELD ts1.

  LOOP AT tab2.
    ctab2-no = tab2-no.
    ctab2-score = tab2-score.
    COLLECT ctab2 INTO ctab2.
  ENDLOOP.

  LOOP AT tab1.
    READ TABLE ctab2 WITH KEY no = tab1-no BINARY SEARCH.
    tab3-name = tab1-name.
    tab3-score = ctab2-score.
    APPEND tab3.
    CLEAR tab3.
  ENDLOOP.

  GET TIME STAMP FIELD ts2.

  ts = ts2 - ts1.
  WRITE: ts.
ENDFORM.                                                    "frm_3

 

外層循環條目 內層循環條目 第一種方式執行時間 第二種方式執行時間 第三種方式執行時間
10 10000 0.000 0.015 0.032
100 10000 0.125 0.188 0.390
10000 4 0.016 0.032 0.016
10000 10 0.031 0.047 0.047
10000 100 0.157 0.235 0.406
1000 1000 0.125 0.204 0.390

 

 

 

 

 

 

  

 

 

 

----------------------------------------------

本博客全部原創文章,未經博主容許,請勿轉載。

----------------------------------------------

相關文章
相關標籤/搜索