平时开发过程中遇到一些复杂的逻辑可能避免不了要用双LOOP循环的场景,这种情况下程序的性能是个很大的问题。数据量大一点的程序动辄3-5分钟,更有甚者直接跑到time out。
最近我学习整理了几种双LOOP循环性能优化的方法,在这里记录并分享一下。
首先,我们写一段没有经过优化的双LOOP循环来看看效果。
REPORT test_loop.
TYPES:BEGIN OF ty_a,
col1(10),
col2(10),
END OF ty_a,
BEGIN OF ty_b,
col1(10),
col3(10),
END OF ty_b,
BEGIN OF ty_c,
col1(10),
col2(10),
col3(10),
END OF ty_c.
DATA:wa_a TYPE ty_a,
wa_b TYPE ty_b,
wa_c TYPE ty_c,
gt_a TYPE TABLE OF ty_a,
gt_b TYPE TABLE OF ty_b,
gt_c TYPE TABLE OF ty_c.
START-OF-SELECTION.
PERFORM frm_getdata.
PERFORM frm_loop.
FORM frm_getdata.
DATA lv_line(5) TYPE n.
DO 5000 TIMES.
lv_line = sy-index.
CLEAR wa_a.
wa_a-col1 = 'col1'&& lv_line.
wa_a-col2 = 'col2'&& lv_line.
APPEND wa_a TO gt_a.
CLEAR wa_b.
wa_b-col1 = 'col1'&& lv_line.
wa_b-col3 = 'col3'&& lv_line.
APPEND wa_b TO gt_b.
ENDDO.
ENDFORM.
FORM frm_loop.
DATA lv_t TYPE i.
GET RUN TIME FIELD DATA(time1).
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b INTO wa_b WHERE col1 = wa_a-col1.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'未经优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.
执行结果:
优化方法1:排序表优化
定义一个排序表并赋值给它,使用排序表进行LOOP循环。
FORM frm_loop_sort.
GET RUN TIME FIELD DATA(time1).
DATA:gt_b_sort TYPE SORTED TABLE OF ty_b WITH NON-UNIQUE KEY col1.
SORT gt_b BY col1.
gt_b_sort[] = gt_b[].
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b_sort INTO wa_b WHERE col1 = wa_a-col1.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
REFRESH gt_c.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'经排序表优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.
执行结果:
优化方法2:内表排序INDEX优化
对标准表进行排序并使用INDEX方式进行优化,此方法使用有局限性,要求gt_a-col1不能重复,一旦重复,结果就不对了。
FORM frm_sort_index.
GET RUN TIME FIELD DATA(time1).
DATA:i TYPE i.
SORT:gt_a BY col1,
gt_b BY col1.
i = 1.
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b INTO wa_b FROM i.
IF wa_a-col1 <> wa_b-col1.
i = sy-tabix.
EXIT.
ENDIF.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
REFRESH gt_c.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'经内表排序INDEX优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.
执行结果:
暂时先写这两种优化方法,其它方法后面再继续加。
完整代码:
REPORT test_loop.
TYPES:BEGIN OF ty_a,
col1(10),
col2(10),
END OF ty_a,
BEGIN OF ty_b,
col1(10),
col3(10),
END OF ty_b,
BEGIN OF ty_c,
col1(10),
col2(10),
col3(10),
END OF ty_c.
DATA:wa_a TYPE ty_a,
wa_b TYPE ty_b,
wa_c TYPE ty_c,
gt_a TYPE TABLE OF ty_a,
gt_b TYPE TABLE OF ty_b,
gt_c TYPE TABLE OF ty_c,
lv_t TYPE i.
START-OF-SELECTION.
PERFORM frm_getdata.
PERFORM frm_loop.
PERFORM frm_loop_sort.
PERFORM frm_sort_index.
PERFORM frm_hs_group.
FORM frm_getdata.
DATA lv_line(5) TYPE n.
DO 5000 TIMES.
lv_line = sy-index.
CLEAR wa_a.
wa_a-col1 = 'col1'&& lv_line.
wa_a-col2 = 'col2'&& lv_line.
APPEND wa_a TO gt_a.
CLEAR wa_b.
wa_b-col1 = wa_a-col1.
wa_b-col3 = 'col3'&& lv_line.
APPEND wa_b TO gt_b.
ENDDO.
ENDFORM.
FORM frm_loop.
GET RUN TIME FIELD DATA(time1).
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b INTO wa_b WHERE col1 = wa_a-col1.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
REFRESH gt_c.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'未经优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.
FORM frm_loop_sort.
GET RUN TIME FIELD DATA(time1).
DATA:gt_b_sort TYPE SORTED TABLE OF ty_b WITH NON-UNIQUE KEY col1.
SORT gt_b BY col1.
gt_b_sort[] = gt_b[].
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b_sort INTO wa_b WHERE col1 = wa_a-col1.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
REFRESH gt_c.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'经排序表优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.
FORM frm_sort_index.
GET RUN TIME FIELD DATA(time1).
SORT:gt_a BY col1,
gt_b BY col1.
LOOP AT gt_a INTO wa_a.
LOOP AT gt_b INTO wa_b FROM sy-tabix.
IF wa_a-col1 <> wa_b-col1.
EXIT.
ENDIF.
wa_c-col1 = wa_a-col1.
wa_c-col2 = wa_a-col2.
wa_c-col3 = wa_b-col3.
APPEND wa_c TO gt_c.
CLEAR wa_c.
ENDLOOP.
ENDLOOP.
REFRESH gt_c.
GET RUN TIME FIELD DATA(time2).
lv_t = time2 - time1.
WRITE:/'经内表排序INDEX优化,5000条数据执行时间:',lv_t,'微秒'.
ENDFORM.