Saturday, December 16, 2006

Performance Tips - Netsed Loops

Performance tuning is they key concept in ABAP programming. In real time, we could find large amount of data. Today we will discuss the worse effect of nested loops and what are the alternate ways to handle nested loops.
If the amount of data is large, nested loops are fully avoided due to performance issues. If your program is extracting small amount of data, then focus on SELECT statements than nested loops.
See below program where you can find three methods:
1) Nested Loop
2) Indexed Loop
3) Parallel Cursor

The indexed loop is the best method to avoid performance issues. Read statement by using binary search inside a loop works well.

The above three methods are depicted in the following program:

report ztest_nested_loop.

data: bkpf type bkpf,
bseg type bseg.

select-options: s_bukrs for bseg-bukrs memory id buk obligatory,
s_gjahr for bseg-gjahr memory id gjr obligatory,
s_lifnr for bseg-lifnr memory id lif obligatory.

data: bkpf_tab type standard table of bkpf,
bkpf_lin like line of bkpf_tab,
bseg_tab type standard table of bseg,
bseg_lin like line of bseg_tab.

data: start_time type sy-uzeit,
end_time type sy-uzeit,
difference type sy-uzeit,
bkpf_entries type sy-tabix,
bseg_entries type sy-tabix,
bkpf_reads type sy-tabix,
bseg_reads type sy-tabix.

start-of-selection.
perform unindexed_select.
perform nested_loop.
perform indexed_loop.
PERFORM parallel_cursor.

*&---------------------------------------------------------------------*
*& Form unindexed_select
*&---------------------------------------------------------------------*
form unindexed_select.

get time field start_time.

select * from bseg
into table bseg_tab
where bukrs in s_bukrs
and gjahr in s_gjahr
and lifnr in s_lifnr.

if sy-subrc <> 0.
message id '00' type 'E' number '001' with 'No entries selected'.
endif.

select * from bkpf
into table bkpf_tab
for all entries in bseg_tab
where bukrs = bseg_tab-bukrs
and belnr = bseg_tab-belnr
and gjahr = bseg_tab-gjahr
and bstat = space.

clear bseg_tab.
refresh bseg_tab.
select * from bseg
into table bseg_tab
for all entries in bkpf_tab
where bukrs = bkpf_tab-bukrs
and belnr = bkpf_tab-belnr
and gjahr = bkpf_tab-gjahr.

get time field end_time.
difference = end_time - start_time.
describe table bkpf_tab lines bkpf_entries.
describe table bseg_tab lines bseg_entries.

write: /001 'Time for unindexed select:', difference,
/005 'Number of BKPF entries:', bkpf_entries,
/005 'Number of BSEG entries:', bseg_entries.
skip 1.

endform. " unindexed_select

*&---------------------------------------------------------------------*
*& Form nested_loop
*&---------------------------------------------------------------------*
form nested_loop.

get time field start_time.

loop at bkpf_tab
into bkpf_lin.
bkpf_reads = bkpf_reads + 1.
loop at bseg_tab
into bseg_lin where
bukrs = bkpf_lin-bukrs and
belnr = bkpf_lin-belnr and
gjahr = bkpf_lin-gjahr.
bseg_reads = bseg_reads + 1.
endloop.
endloop.

get time field end_time.
difference = end_time - start_time.

write: /001 'Time for nested loop:', difference,
/005 'Number of BKPF reads:', bkpf_reads,
/005 'Number of BSEG reads:', bseg_reads.
skip 1.

endform. " nested_loop

*&---------------------------------------------------------------------*
*& Form indexed_loop
*&---------------------------------------------------------------------*
form indexed_loop.

data: bkpf_index like sy-tabix,
bseg_index like sy-tabix.

clear: bkpf_reads,
bseg_reads.

get time field start_time.

sort: bkpf_tab by bukrs belnr gjahr,
bseg_tab by bukrs belnr gjahr.

loop at bkpf_tab
into bkpf_lin.
read table bseg_tab
into bseg_lin
with key
bukrs = bkpf_lin-bukrs
belnr = bkpf_lin-belnr
gjahr = bkpf_lin-gjahr
binary search.
bkpf_reads = bkpf_reads + 1.
bseg_index = sy-tabix.
while sy-subrc = 0.
bseg_index = bseg_index + 1.
bseg_reads = bseg_reads + 1.
read table bseg_tab
into bseg_lin
index bseg_index.
if bseg_lin-bukrs <> bkpf_lin-bukrs or
bseg_lin-belnr <> bkpf_lin-belnr or
bseg_lin-gjahr <> bkpf_lin-gjahr.
sy-subrc = 99.
else.
endif.
endwhile.
endloop.

get time field end_time.
difference = end_time - start_time.

write: /001 'Time for indexed loop:', difference,
/005 'Number of BKPF reads:', bkpf_reads,
/005 'Number of BSEG reads:', bseg_reads.
skip 1.

endform. " indexed_loop

*&---------------------------------------------------------------------*
*& Form parallel_cursor
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM parallel_cursor.

DATA: bkpf_index LIKE sy-tabix,
bseg_index LIKE sy-tabix.

CLEAR: bkpf_reads,
bseg_reads.

GET TIME FIELD start_time.

SORT: bkpf_tab BY bukrs belnr gjahr,
bseg_tab BY bukrs belnr gjahr.

bseg_index = 1.
LOOP AT bkpf_tab
INTO bkpf_lin.
bkpf_reads = bkpf_reads + 1.
LOOP AT bseg_tab INTO bseg_lin FROM bseg_index.
IF bseg_lin-bukrs <> bkpf_lin-bukrs OR
bseg_lin-belnr <> bkpf_lin-belnr OR
bseg_lin-gjahr <> bkpf_lin-gjahr.
bseg_index = sy-tabix.
EXIT.
ELSE.
bseg_reads = bseg_reads + 1.
ENDIF.
ENDLOOP.
ENDLOOP.

GET TIME FIELD end_time.
difference = end_time - start_time.

WRITE: /001 'Time for parallel cursor :', difference,
/005 'Number of BKPF reads :', bkpf_reads,
/005 'Number of BSEG reads :', bseg_reads.

ENDFORM. " parallel_cursor

0 comments:

Blogger template 'YellowFlower' by Ourblogtemplates.com 2008