Reputation: 4335
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. 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?
Upvotes: 1
Views: 2975
Reputation: 1
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
Upvotes: 0
Reputation: 5554
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.
I would also use a sy-tabix variable to keep the position of the row and use it then like this:
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.
That, in my opinion, could improve the performance because you would loop only over one table.
Hope it helps.
Upvotes: 2
Reputation: 2565
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; 2. The order of ZMARD is not important for the report;
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.
Upvotes: 2
Reputation: 4592
It seems this code wants to update ZMARD-LABST
for all entries in ZMARD. 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. 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. I hope that either your LGORT values do not cross WERKS or that ZCOMB has a WERKS field that you can use.
Upvotes: 1
Reputation: 1851
Hello sure there are some possibilities.
First: You can conditionize the inner loop with "where outer looped struct-field" = "inner loop table field".
Second: You can use hashed tables. But those are more important for read table.
Upvotes: 3