Improve nested loop performance with ABAP
In this article I would like to resume how it is possible to improve performance of our report using some tips.
Consider this scenario:
We have two itabs with Accounting Document Header (BKPF) and Accounting Document Segment (BSEG) and we need to perform some logic in all documents’ positions.
How we can do this in a efficient way?
The worst solution is to perform a loop for each document and then find the position with a full loop in the segments’ table.
LOOP AT lt_bkpf INTO ls_bkpf.
LOOP AT lt_bseg INTO ls_bseg.
lv_counter = lv_counter + 1.
IF ls_bseg-BUKRS = ls_bkpf-BUKRS AND
ls_bseg-BELNR = ls_bkpf-BELNR AND
ls_bseg-GJAHR = ls_bkpf-GJAHR.
** Your logic **
ENDIF.
ENDLOOP.
ENDLOOP.
This is not a crafty approach, we perform a lot of unneeded cycles. We try to improve performance using the WHERE clause in the second LOOP.
LOOP AT lt_bkpf INTO ls_bkpf.
LOOP AT lt_bseg INTO ls_bseg WHERE
BUKRS = ls_bkpf-BUKRS AND
BELNR = ls_bkpf-BELNR AND
GJAHR = ls_bkpf-GJAHR.
lv_counter = lv_counter + 1.
** Your logic **
ENDLOOP.
ENDLOOP.
Now we have significantly reduced the number of cycles and also the execution time. Are we sure that we can do nothing else to decrease execution time?
ABAP LOOP statement has the possibility to use a cursor, in other words, if we have sorted tables we will be able to start looping from the first item, that we are looking for, other items will be in the next positions.
SORT lt_bkpf BY BUKRS BELNR GJAHR.
SORT lt_bseg BY BUKRS BELNR GJAHR.
LOOP AT lt_bkpf INTO ls_bkpf.
READ TABLE lt_bseg TRANSPORTING NO FIELDS WITH KEY
BUKRS = ls_bkpf-BUKRS
BELNR = ls_bkpf-BELNR
GJAHR = ls_bkpf-GJAHR.
CHECK sy-subrc = 0.
LOOP AT lt_bseg INTO ls_bseg FROM sy-tabix.
lv_counter = lv_counter + 1.
** Your logic **
AT END OF GJAHR.
EXIT.
ENDAT.
ENDLOOP.
ENDLOOP.
Using sorted table we can execute READ TABLE statement using the BINARY SEARCH option, this will improve its efficency.
SORT lt_bkpf BY BUKRS BELNR GJAHR.
SORT lt_bseg BY BUKRS BELNR GJAHR.
LOOP AT lt_bkpf INTO ls_bkpf.
READ TABLE lt_bseg TRANSPORTING NO FIELDS WITH KEY
BUKRS = ls_bkpf-BUKRS
BELNR = ls_bkpf-BELNR
GJAHR = ls_bkpf-GJAHR BINARY SEARCH.
CHECK sy-subrc = 0.
LOOP AT lt_bseg INTO ls_bseg FROM sy-tabix.
lv_counter = lv_counter + 1.
** Your logic **
AT END OF GJAHR.
EXIT.
ENDAT.
ENDLOOP.
ENDLOOP.
In this way we have improved our loop execution time, but we can do something else to speed up our algorithm, we can use the field symbols.
SORT lt_bkpf BY BUKRS BELNR GJAHR.
SORT lt_bseg BY BUKRS BELNR GJAHR.
LOOP AT lt_bkpf ASSIGNING <ls_bkpf>
READ TABLE lt_bseg TRANSPORTING NO FIELDS WITH KEY
BUKRS = <ls_bkpf>-BUKRS
BELNR = <ls_bkpf>-BELNR
GJAHR = <ls_bkpf>-GJAHR BINARY SEARCH.
CHECK sy-subrc = 0.
LOOP AT lt_bseg ASSIGNING <ls_bseg> FROM sy-tabix.
lv_counter = lv_counter + 1.
** Your logic **
AT END OF GJAHR.
EXIT.
ENDAT.
ENDLOOP.
ENDLOOP.
Table below summarizes the different algorithms efficiency using increasing amount of data, as you can see the use of these improvements is more important with large itabs.
The percentages shows the gain obtained related to the worst case.
Test were performed on SAP ECC 6.0, results may be different on other environment.
Hope this could help you.
Best wishes,
Ivan
No related posts.
Feeling lucky to come across your site.
i would love to add your site to my directory under ABAP at http://social.sapdocs.info
i hope it is ok for you
wish u my best.
cheers~