嵌套循环的效率问题

不少人说,上了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

 

 

 

 

 

 

  

 

 

 

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

本博客全部原创文章,未经博主容许,请勿转载。

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

相关文章
相关标签/搜索