最近优化了一部分程序,基本都是嵌套循环导致的效率低下;ABAP开发时会尽量避免使用嵌套循环,但是实际应用场景绕不开嵌套循环;针对嵌套循环优化,比较常见的优化方式为二分法read+loop index处理,这里通过一个demp程序更好的分析下嵌套循环相关的效率。
1. 针对嵌套循环使用使用二分法read+loop index处理效率优化方面最优,胜于使用排序表
2. loop index 做条件筛选时占用时间极少,几乎可以忽略不计
3. 针对内表读取二分法read效率最佳,尽管排序表使用key做关联,默认使用二分法
4. read 遍历效率远优于loop where 遍历效率
1. read table binary search 随着数据表条目的增加,增加的时间比loop using key更多,但是如下1000000条数据结果,仍然有差距。
2. 使用hash表 primary key read效率比二分法更优(hash表primary key主键必须唯一,read table 时采用hash算法,因此不适用循环嵌套)
其它demo输出数据
1. 循环中使用read时,尽量使用二分法,且尽量loop小表,read大表
2. loop 嵌套循环时,外层循环放小表效率更优
3. 如果主键确定的read可以考虑使用hash表优化效率
4. loop where 遍历效率较低,带where条件遍历仅为无where条件遍历时的一半,这是嵌套循环耗费时间的原因之一。
实际处理嵌套循环时遵循使用效率更高的语句处理大表,较低的处理小表原则
效率排序
loop 无条件 read < sorted table read < binary search < hash primary key 1. 由于系统差异,测试结果存在有一定差异,实践出真知。 2. hash表sorted key 效果和排序表一致,hash key需要唯一主键,没有计入测试。 https://mp.csdn.net/mp_blog/creation/editor/125475812 Demo程序附
*&------------------------------------------------------------------*
*& Report ZDEOMO
*&------------------------------------------------------------------*
*&Author : Fireworks *
*&Description : 嵌套循环场景效率测试 *
*&------------------------------------------------------------------*
REPORT zdemo.
*&---------------------------------------------------------------------*
* DATA Declare
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_alv_out,
test_scenario TYPE text50,
mode TYPE i,
loop_index TYPE sy-index,
timestampb TYPE tzntstmpll,
timestampe TYPE tzntstmpll,
spendtime TYPE i,
END OF ty_alv_out.
TYPES: BEGIN OF ty_subroutines,
form TYPE char30,
test_scenario TYPE text50,
mode TYPE i,
END OF ty_subroutines.
TYPES: BEGIN OF ty_test_itab,
key_char TYPE char2,
key_num TYPE numc3,
int TYPE sy-index,
field_1 TYPE text30,
END OF ty_test_itab.
TYPES: tt_alv_out TYPE TABLE OF ty_alv_out.
DATA: gt_itab_01 TYPE TABLE OF ty_test_itab,
gt_itab_02 TYPE TABLE OF ty_test_itab,
gt_subroutines TYPE TABLE OF ty_subroutines.
DATA gv_mode TYPE i.
DATA: gt_alv_out TYPE tt_alv_out,
go_salv TYPE REF TO cl_salv_table,
go_display_settings TYPE REF TO cl_salv_display_settings.
*&---------------------------------------------------------------------*
* SELECTION-SCREEN
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1.
PARAMETERS: p_loop TYPE numc3.
PARAMETERS: p_dc01 TYPE i.
PARAMETERS: p_dc02 TYPE i.
SELECTION-SCREEN END OF BLOCK b1.
*&---------------------------------------------------------------------*
* START-OF-SELECTION
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM generate_test_data.
PERFORM set_scenario.
PERFORM process_scenario.
PERFORM data_process_befor_output.
PERFORM output.
*&---------------------------------------------------------------------*
*& Form GENERATE_TEST_DATA
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM generate_test_data .
DATA: lo_random TYPE REF TO cl_abap_random,
lv_seed TYPE i,
lv_min_limit TYPE i,
lv_max_limit TYPE i,
lv_range_num TYPE i.
DATA: ls_itab_01 TYPE ty_test_itab,
ls_itab_02 TYPE ty_test_itab.
DATA: lv_i TYPE i,
lv_text TYPE text20.
CONSTANTS c_char TYPE char50 VALUE '1234567890QWERTYUIOPASDFGHJKLZXCVBNM'.
CONSTANTS c_text TYPE char80 VALUE '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'.
lv_seed = cl_abap_random=>seed( ).
lo_random = cl_abap_random=>create( seed = lv_seed ).
DO p_dc01 TIMES.
CLEAR: ls_itab_01-key_char,ls_itab_01-key_num.
ls_itab_01-int = sy-index.
DO 2 TIMES.
lv_min_limit = 0 .
lv_max_limit = 35 .
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_01-key_char = ls_itab_01-key_char && c_char+lv_range_num(1).
ENDDO.
lv_min_limit = 0 .
lv_max_limit = 999.
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_01-key_num = lv_range_num.
lv_min_limit = 0 .
lv_max_limit = 61 .
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_01-field_1 = lv_text && ls_itab_01-field_1.
ls_itab_01-field_1+lv_i(1) = c_text+lv_range_num(1).
APPEND ls_itab_01 TO gt_itab_01.
lv_i = lv_range_num MOD 30.
lv_text = ls_itab_01-field_1+6(2).
ENDDO.
DO p_dc02 TIMES.
CLEAR: ls_itab_02-key_char,ls_itab_02-key_num.
ls_itab_02-int = sy-index.
DO 2 TIMES.
lv_min_limit = 0 .
lv_max_limit = 35 .
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_02-key_char = ls_itab_02-key_char && c_char+lv_range_num(1).
ENDDO.
lv_min_limit = 0 .
lv_max_limit = 999.
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_02-key_num = lv_range_num.
lv_min_limit = 0 .
lv_max_limit = 61 .
lv_range_num = lo_random->intinrange( low = lv_min_limit high = lv_max_limit ).
ls_itab_02-field_1 = lv_text && ls_itab_02-field_1.
ls_itab_02-field_1+lv_i(1) = c_text+lv_range_num(1).
APPEND ls_itab_02 TO gt_itab_02.
lv_i = lv_range_num MOD 30.
lv_text = ls_itab_02-field_1+6(2).
ENDDO.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form SET_SCENARIO
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM set_scenario .
DATA ls_subroutines TYPE ty_subroutines.
ls_subroutines-test_scenario = '循环1表嵌套2表'.
ls_subroutines-form = 'LOOP2LOOP'.
ls_subroutines-mode = 1.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表嵌套1表'.
ls_subroutines-form = 'LOOP2LOOP'.
ls_subroutines-mode = 2.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环1表嵌套2排序表'.
ls_subroutines-form = 'LOOP2LOOP3'.
ls_subroutines-mode = 3.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表嵌套1排序表'.
ls_subroutines-form = 'LOOP2LOOP3'.
ls_subroutines-mode = 4.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环1表嵌套2表优化'.
ls_subroutines-form = 'LOOP2LOOP2'.
ls_subroutines-mode = 5.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表嵌套1表优化'.
ls_subroutines-form = 'LOOP2LOOP2'.
ls_subroutines-mode = 6.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环1表读取2表'.
ls_subroutines-form = 'LOOP2READ'.
ls_subroutines-mode = 7.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表读取1表'.
ls_subroutines-form = 'LOOP2READ'.
ls_subroutines-mode = 8.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环1表二分读取2表'.
ls_subroutines-form = 'LOOP2READ2'.
ls_subroutines-mode = 9.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表二分读取1表'.
ls_subroutines-form = 'LOOP2READ2'.
ls_subroutines-mode = 10.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环1表key读取2表'.
ls_subroutines-form = 'LOOP2READ3'.
ls_subroutines-mode = 11.
APPEND ls_subroutines TO gt_subroutines.
ls_subroutines-test_scenario = '循环2表key读取1表'.
ls_subroutines-form = 'LOOP2READ3'.
ls_subroutines-mode = 12.
APPEND ls_subroutines TO gt_subroutines.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form PROCESS_SCENARIO
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM process_scenario .
DATA: ls_subroutines TYPE ty_subroutines,
ls_alv_out TYPE ty_alv_out.
DATA: lv_timestamp TYPE tzonref-tstampl.
DO p_loop TIMES.
LOOP AT gt_subroutines INTO ls_subroutines.
ls_alv_out-loop_index = sy-index.
ls_alv_out-mode = ls_subroutines-mode.
ls_alv_out-test_scenario = ls_subroutines-test_scenario.
GET TIME STAMP FIELD lv_timestamp.
ls_alv_out-timestampb = lv_timestamp * 1000000.
gv_mode = ls_subroutines-mode.
PERFORM (ls_subroutines-form) IN PROGRAM.
GET TIME STAMP FIELD lv_timestamp.
ls_alv_out-timestampe = lv_timestamp * 1000000.
ls_alv_out-spendtime = ls_alv_out-timestampe - ls_alv_out-timestampb.
APPEND ls_alv_out TO gt_alv_out.
ENDLOOP.
ENDDO.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form DATA_PROCESS_BEFOR_OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM data_process_befor_output .
DATA: lv_max_time TYPE i,
lv_min_time TYPE i,
lv_all_time TYPE p LENGTH 10,
lt_alv_out TYPE TABLE OF ty_alv_out,
ls_alv_out TYPE ty_alv_out.
FIELD-SYMBOLS: