简体   繁体   English

加速 ABAP 中的长运行循环

[英]Speedup long running loop in ABAP

When analysing a performance issue in an SAP export script (SAP R/3, 4.06b) I found the following code which runs about 10 minutes in the test system.在分析 SAP 导出脚本 (SAP R/3, 4.06b) 中的性能问题时,我发现以下代码在测试系统中运行了大约 10 分钟。 Might be a bit faster in production but I can not test it there.在生产中可能会快一点,但我无法在那里进行测试。

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.

Do you have any advice on how this loops can be optimized / put together into one single loop?对于如何优化此循环/将它们组合成一个循环,您有什么建议吗?

Hello sure there are some possibilities.你好肯定有一些可能性。

First: You can conditionize the inner loop with "where outer looped struct-field" = "inner loop table field".第一:您可以使用“where external looped struct-field” = “inner loop table field”来调节内循环。

Second: You can use hashed tables.第二:您可以使用哈希表。 But those are more important for read table.但是这些对于读取表来说更重要。

I think you should filter the inner loop.我认为你应该过滤内循环。 Additionally, I would define the tables as SORTED tables (WITH NON-SORTED KEY), at least 'ZCOMB' with keys MATNR, LGORT and perhaps IND.此外,我会将这些表定义为 SORTED 表(WITH NON-SORTED KEY),至少是带有键 MATNR、LGORT 和 IND 的“ZCOMB”。

I would also use a sy-tabix variable to keep the position of the row and use it then like this:我还会使用 sy-tabix 变量来保持行的位置,然后像这样使用它:

MODIFY ZMARD INDEX lv_tabix.

Or I could use a field symbol.或者我可以使用字段符号。 It's your decision.是你的选择。

The code would look like this:代码如下所示:

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.

Finally, another approach, in my opinion, would be to loop over 'ZCOMB' and use COLLECT to sum the data and with those sums modify 'ZMARD' reading the table with BINARY SEARCH.最后,在我看来,另一种方法是遍历“ZCOMB”并使用 COLLECT 对数据求和,并使用这些总和修改“ZMARD”,使用 BINARY SEARCH 读取表。

That, in my opinion, could improve the performance because you would loop only over one table.在我看来,这可以提高性能,因为您只会循环一张表。

Hope it helps.希望能帮助到你。

This is a classical case where two tables need to be intersected.这是需要将两个表相交的经典案例。 The code in your example is one of the worst ways to do it and can be dramatically improved.您示例中的代码是最糟糕的方法之一,可以显着改进。 Here is an interesting article about that.这是一篇关于此的有趣文章

And here is that implemented for your example.这是为您的示例实现的。

Assumptions: 1. ZMARD has no duplicate entries for a MATNR LGORT combination;假设: 1. ZMARD 对于 MATNR LGORT 组合没有重复条目; 2. The order of ZMARD is not important for the report; 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.

Please note that I just edited this code here so I expect it will have some syntax errors and bugs.请注意,我刚刚在这里编辑了这段代码,所以我预计它会有一些语法错误和错误。

It seems this code wants to update ZMARD-LABST for all entries in ZMARD.似乎这段代码想要更新ZMARD-LABST中所有条目的ZMARD-LABST LABST。 Looping over table within a table loop seems really slow to do that.在表循环中循环表似乎真的很慢。 If you sorted ZMARD on MATNR, then you could do this in 2 distinct loops.如果您在 MATNR 上对 ZMARD 进行排序,那么您可以在 2 个不同的循环中执行此操作。 Something like就像是

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.

Note that MARD has 3 keys: MATNR, BUKRS, and LGORT.请注意,MARD 有 3 个键:MATNR、BUKRS 和 LGORT。 I hope that either your LGORT values do not cross WERKS or that ZCOMB has a WERKS field that you can use.我希望您的 LGORT 值不会与 WERKS 交叉,或者 ZCOMB 有一个您可以使用的 WERKS 字段。

If you don't care about execution order you can do this (untested):如果你不关心执行顺序,你可以这样做(未经测试):

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

ENDLOOP.端环。 " ZMARD loop " ZMARD 循环

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM