ネストされたサイクルの効率の問題

18972 ワード

多くの人は、HANAに行くと、効率はもう問題ではないと言っています.
大量のデータ処理に遭遇する場合、SQLクエリーの時間はできるだけ低く最適化された後、ABAP処理時間は高くなりません.不合理なネストサイクルがCPUに与える負担はHANAで解決できるのではないか.
だから、レポートの検索が遅すぎるのはデータベースの応答時間が長すぎるせいで、ひたすらHANAに頼ってレポートの問題を解決して、このような態度はいけません!
 
本稿では、ネストされたループを最適化するためのいくつかの考え方を提供し、20分から数秒に短縮したいと考えています.
【完全なテストコードとテスト結果は本明細書の末尾を参照】
 
ケース:
内表TAB 1——学号、氏名.3万本です.
内表TAB 2——学号、課程、成績.30万本です.
現在、TAB 1とTAB 2は既に入手されており、手動で並べ替えられており、定義時はTYPE STANDARD TABLE OFの方式で定義されているが、現在、TAB 1とTAB 2から各学生の成績総点を算出するよう求められている.
注意:コードをタップしやすいように、本明細書のすべての内部テーブルは、ヘッダー付きの内部テーブルです.
 
一般的な書き方:
LOOP AT TAB1.

  LOOP AT TAB2 WHERE   = TAB1- .

     .

    APPEND ... TO  . 

  ENDLOOP.

ENDLOOP.

このように書くと、20分もデータが出ないかもしれません.
原因分析:標準表(STANDARD TABLE)に対して、LOOP..WHERE..行ごとに判断を実行します.このような書き方は,実際には3 W*30 Wサイクルを実行している.
 
ネストされたループの効率を向上させるためには,ループ回数を減らす.これは根本的な出発点です!
 
最適化方法1[推奨]:
TAB 2の定義を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:
TAB 2をソートテーブルに変更し、コードは共通コードと一致します.
原因分析:
ソートテーブルの場合、LOOP..WHERE..標準表のLOOPより..WHERE..もっと速くしなければなりません.
しかし、この例では、この方式の効率は、方式1の効率の約半分である(詳細な試験時間の比較は、本明細書の末尾を参照).【サーバやクライアントによって差が生じる場合があります.また、第2の方法が第1の方法よりも速い場合もあります.】
 
最適化方式3:【内層データをまとめる必要があり、かつ内層の単回循環量が少ないため、推奨使用】
学号と成績を含むTAB 3を定義します.
LOOP AT TAB2.

  TAB3-  = TAB2- .

  TAB3-  = TAB2- .

  COLLECT TAB3.

ENDLOOP.

SORT TAB3 BY  .

LOOP AT TAB1.

  READ TAB3 WITH KEY   = TAB1-  BINARY SEARCH.

  " 

ENDLOOP.

 
原因分析:
サイクル数、TAB 2、30 W回;TAB 1,3 W回.全部で33 W回です.
 
テストコード:
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

 
外層ループエントリ
内側ループエントリ
第1の方式の実行時間
第2の方式の実行時間
第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
 
 
 
 
 
 
  
 
 
 
----------------------------------------------
このブログのすべてのオリジナル文章は、ブロガーの許可を得ずに転載しないでください.
----------------------------------------------