在 ABAP 中加速长 运行 循环
Speedup long running loop in ABAP
在分析 SAP 导出脚本 (SAP R/3, 4.06b) 中的性能问题时,我发现以下代码在测试系统中运行了大约 10 分钟。在生产中可能会快一点,但我无法在那里进行测试。
LOOP AT ZMARD.
LOOP AT ZCOMB.
IF ZCOMB-MATNR = ZMARD-MATNR.
IF ZCOMB-LGORT = ZMARD-LGORT.
IF ZCOMB-IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDIF. "IND
ENDIF. "LGORT
ENDIF. "MATNR
ENDLOOP.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD.
ENDLOOP.
对于如何优化这些循环/将其组合成一个循环,您有什么建议吗?
你好,确实有一些可能性。
首先:您可以使用 "where outer looped struct-field" = "inner loop table field" 条件化内部循环。
其次:您可以使用哈希 tables。但这些对于阅读 table.
更重要
我认为你应该过滤内循环。此外,我会将 tables 定义为 SORTED tables (WITH NON-SORTED KEY),至少 'ZCOMB' 具有键 MATNR、LGORT 和可能的 IND。
我还会使用 sy-tabix 变量来保持行的位置,然后像这样使用它:
MODIFY ZMARD INDEX lv_tabix.
或者我可以使用字段符号。这是你的决定。
代码如下所示:
DATA lv_index type sy-tabix.
LOOP AT ZMARD.
lv_index = sy-tabix.
LOOP AT ZCOMB WHERE MATNR = ZMARD-MATNR AND LGORT = ZMARD-LGORT AND IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDLOOP.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX lv_index.
ENDLOOP.
最后,在我看来,另一种方法是遍历 'ZCOMB' 并使用 COLLECT 对数据求和,然后用这些求和修改 'ZMARD' 读取 table 和 BINARY搜索。
在我看来,这可以提高性能,因为你只会循环一个 table。
希望对您有所帮助。
似乎这段代码想要更新 ZMARD 中所有条目的 ZMARD-LABST
。在 table 循环中循环 table 似乎真的很慢。如果您在 MATNR 上对 ZMARD 进行排序,那么您可以在 2 个不同的循环中执行此操作。像
DATA lv_tabix type sy-tabix.
FIELD-SYMBOLS <MARD> like ZMARD. "I dont know the type of ZMARD
SORT ZCOMB BY MATNR.
LOOP AT ZCOMB.
IF ZCOMB-IND NE ' '.
CONTINUE.
ENDIF.
IF <MARD>-MATNR NE ZCOMB-MATNR OR <MARD>-LGORT NE ZCOMB-LGORT.
"This could be a binary read, because of sorting we only do a read per material
READ TABLE MARD ASSIGNING <MARD> WITH KEY MATNR = ZCOMB-MATNR LGORT = ZCOMB-LGORT.
IF SY-SUBRC NE 0.
CONTINUE.
ENDIF.
ENDIF.
IF ZCOMB-PLUMI = '+'.
ADD ZCOMB-MNG01 TO <MARD>-LABST.
ELSEIF ZCOMB-PLUMI = '-'.
SUBTRACT ZCOMB-MNG01 FROM <MARD>-LABST.
ENDIF.
ENDLOOP.
LOOP AT ZMARD.
lv_index = sy-tabix.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX lv_tabix.
ENDLOOP.
请注意,MARD 有 3 个密钥:MATNR、BUKRS 和 LGORT。我希望您的 LGORT 值不会与 WERKS 交叉,或者 ZCOMB 有一个您可以使用的 WERKS 字段。
这是一个典型的案例,需要对两个表进行交集。您示例中的代码是最糟糕的方法之一,可以显着改进。这是一个 interesting article 关于那个。
这是为您的示例实现的。
假设:
1. ZMARD对于MATNR LGORT组合没有重复条目;
2. ZMARD的顺序对报告不重要;
DATA: IX_MARD TYPE I,
IX_COMB TYPE I.
DEFINE READ_NEXT.
ADD 1 TO IX_&1.
READ TABLE Z&1 INDEX IX_&1.
IF SY-SUBRC NE 0.
IX_&1 = -1.
ENDIF.
END-OF-DEFINITION.
" It would be better if these sorts were done
" in the SELECT of the data
SORT ZMARD BY MATNR LGORT.
SORT ZCOMB BY MATNR LGORT.
IX_MARD = IX_COMB = 0.
READ_NEXT: MARD, COMB.
WHILE IX_MARD GT 0 AND IX_COMB GT 0.
IF ZMARD-MATNR EQ ZCOMB-MATNR AND
ZMARD-LGORT EQ ZCOMB-LGORT.
" Match between MARD and COMB
IF ZCOMB-IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDIF. "IND
READ_NEXT: COMB.
ELSEIF ZMARD-MATNR LT ZCOMB-MATNR OR
( ZMARD-MATNR EQ ZCOMB-MATNR AND
ZMARD-LGORT LT ZCOMB-LGORT
).
" MARD behind COMB
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX IX_MARD.
READ_NEXT MARD.
ELSE.
" MARD ahead of COMB
READ_NEXT COMB.
ENDIF. " Match on material and storage location
ENDWHILE.
WHILE IX_MARD GT 0.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX IX_MARD.
READ_NEXT MARD.
ENDWHILE.
请注意,我刚刚在这里编辑了这段代码,所以我预计它会有一些语法错误和错误。
如果您不关心执行顺序,您可以这样做(未经测试):
SORT ZMARD BY MATNR LGORT.
SORT ZCOMB BY MATNR LGORT.
LOOP AT ZMARD ASSIGNING <ZMARD>.
READ TABLE ZCOMB WITH KEY
MATNR = <ZMARD>-MATNR
LGORT = <ZMARD>-LGORT
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
lv_index = sy-tabix.
ELSE.
CONTINUE.
ENDIF.
LOOP AT ZCOMB ASSIGNING <ZCOMB> FROM lv_index.
IF <ZCOMB>-MATNR <> <ZMARD>-MATNR OR <ZCOMB>-LGORT <> <ZMARD>-LGORT.
EXIT.
ENDIF.
IF <ZCOMB>-IND = ' '.
IF <ZCOMB>-PLUMI = '+'.
<ZMARD>-LABST = <ZMARD>-LABST + <ZCOMB>-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
<ZMARD>-LABST = <ZMARD>-LABST - <ZCOMB>-MNG01.
ENDIF.
ENDIF.
ENDLOOP. " ZCOMB loop
结束循环。 " ZMARD 循环
在分析 SAP 导出脚本 (SAP R/3, 4.06b) 中的性能问题时,我发现以下代码在测试系统中运行了大约 10 分钟。在生产中可能会快一点,但我无法在那里进行测试。
LOOP AT ZMARD.
LOOP AT ZCOMB.
IF ZCOMB-MATNR = ZMARD-MATNR.
IF ZCOMB-LGORT = ZMARD-LGORT.
IF ZCOMB-IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDIF. "IND
ENDIF. "LGORT
ENDIF. "MATNR
ENDLOOP.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD.
ENDLOOP.
对于如何优化这些循环/将其组合成一个循环,您有什么建议吗?
你好,确实有一些可能性。
首先:您可以使用 "where outer looped struct-field" = "inner loop table field" 条件化内部循环。
其次:您可以使用哈希 tables。但这些对于阅读 table.
更重要我认为你应该过滤内循环。此外,我会将 tables 定义为 SORTED tables (WITH NON-SORTED KEY),至少 'ZCOMB' 具有键 MATNR、LGORT 和可能的 IND。
我还会使用 sy-tabix 变量来保持行的位置,然后像这样使用它:
MODIFY ZMARD INDEX lv_tabix.
或者我可以使用字段符号。这是你的决定。
代码如下所示:
DATA lv_index type sy-tabix.
LOOP AT ZMARD.
lv_index = sy-tabix.
LOOP AT ZCOMB WHERE MATNR = ZMARD-MATNR AND LGORT = ZMARD-LGORT AND IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDLOOP.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX lv_index.
ENDLOOP.
最后,在我看来,另一种方法是遍历 'ZCOMB' 并使用 COLLECT 对数据求和,然后用这些求和修改 'ZMARD' 读取 table 和 BINARY搜索。
在我看来,这可以提高性能,因为你只会循环一个 table。
希望对您有所帮助。
似乎这段代码想要更新 ZMARD 中所有条目的 ZMARD-LABST
。在 table 循环中循环 table 似乎真的很慢。如果您在 MATNR 上对 ZMARD 进行排序,那么您可以在 2 个不同的循环中执行此操作。像
DATA lv_tabix type sy-tabix.
FIELD-SYMBOLS <MARD> like ZMARD. "I dont know the type of ZMARD
SORT ZCOMB BY MATNR.
LOOP AT ZCOMB.
IF ZCOMB-IND NE ' '.
CONTINUE.
ENDIF.
IF <MARD>-MATNR NE ZCOMB-MATNR OR <MARD>-LGORT NE ZCOMB-LGORT.
"This could be a binary read, because of sorting we only do a read per material
READ TABLE MARD ASSIGNING <MARD> WITH KEY MATNR = ZCOMB-MATNR LGORT = ZCOMB-LGORT.
IF SY-SUBRC NE 0.
CONTINUE.
ENDIF.
ENDIF.
IF ZCOMB-PLUMI = '+'.
ADD ZCOMB-MNG01 TO <MARD>-LABST.
ELSEIF ZCOMB-PLUMI = '-'.
SUBTRACT ZCOMB-MNG01 FROM <MARD>-LABST.
ENDIF.
ENDLOOP.
LOOP AT ZMARD.
lv_index = sy-tabix.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX lv_tabix.
ENDLOOP.
请注意,MARD 有 3 个密钥:MATNR、BUKRS 和 LGORT。我希望您的 LGORT 值不会与 WERKS 交叉,或者 ZCOMB 有一个您可以使用的 WERKS 字段。
这是一个典型的案例,需要对两个表进行交集。您示例中的代码是最糟糕的方法之一,可以显着改进。这是一个 interesting article 关于那个。
这是为您的示例实现的。
假设: 1. ZMARD对于MATNR LGORT组合没有重复条目; 2. ZMARD的顺序对报告不重要;
DATA: IX_MARD TYPE I,
IX_COMB TYPE I.
DEFINE READ_NEXT.
ADD 1 TO IX_&1.
READ TABLE Z&1 INDEX IX_&1.
IF SY-SUBRC NE 0.
IX_&1 = -1.
ENDIF.
END-OF-DEFINITION.
" It would be better if these sorts were done
" in the SELECT of the data
SORT ZMARD BY MATNR LGORT.
SORT ZCOMB BY MATNR LGORT.
IX_MARD = IX_COMB = 0.
READ_NEXT: MARD, COMB.
WHILE IX_MARD GT 0 AND IX_COMB GT 0.
IF ZMARD-MATNR EQ ZCOMB-MATNR AND
ZMARD-LGORT EQ ZCOMB-LGORT.
" Match between MARD and COMB
IF ZCOMB-IND = ' '.
IF ZCOMB-PLUMI = '+'.
ZMARD-LABST = ZMARD-LABST + ZCOMB-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
ZMARD-LABST = ZMARD-LABST - ZCOMB-MNG01.
ENDIF. "PLUMI
ENDIF. "IND
READ_NEXT: COMB.
ELSEIF ZMARD-MATNR LT ZCOMB-MATNR OR
( ZMARD-MATNR EQ ZCOMB-MATNR AND
ZMARD-LGORT LT ZCOMB-LGORT
).
" MARD behind COMB
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX IX_MARD.
READ_NEXT MARD.
ELSE.
" MARD ahead of COMB
READ_NEXT COMB.
ENDIF. " Match on material and storage location
ENDWHILE.
WHILE IX_MARD GT 0.
IF ZMARD-LABST < 0.
ZMARD-LABST = 0.
ENDIF.
WRITE ZMARD-LABST DECIMALS 0 TO ZMARD-ZLABST.
MODIFY ZMARD INDEX IX_MARD.
READ_NEXT MARD.
ENDWHILE.
请注意,我刚刚在这里编辑了这段代码,所以我预计它会有一些语法错误和错误。
如果您不关心执行顺序,您可以这样做(未经测试):
SORT ZMARD BY MATNR LGORT.
SORT ZCOMB BY MATNR LGORT.
LOOP AT ZMARD ASSIGNING <ZMARD>.
READ TABLE ZCOMB WITH KEY
MATNR = <ZMARD>-MATNR
LGORT = <ZMARD>-LGORT
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
lv_index = sy-tabix.
ELSE.
CONTINUE.
ENDIF.
LOOP AT ZCOMB ASSIGNING <ZCOMB> FROM lv_index.
IF <ZCOMB>-MATNR <> <ZMARD>-MATNR OR <ZCOMB>-LGORT <> <ZMARD>-LGORT.
EXIT.
ENDIF.
IF <ZCOMB>-IND = ' '.
IF <ZCOMB>-PLUMI = '+'.
<ZMARD>-LABST = <ZMARD>-LABST + <ZCOMB>-MNG01.
ELSEIF ZCOMB-PLUMI = '-'.
<ZMARD>-LABST = <ZMARD>-LABST - <ZCOMB>-MNG01.
ENDIF.
ENDIF.
ENDLOOP. " ZCOMB loop
结束循环。 " ZMARD 循环