2015 Jan 21 7:51 PM
I am trying to improve a function module that gets called anywhere between 5 to 45000 times per processing run. In this function module, I found the following select statements:
Original code
SELECT SINGLE kunnr FROM vbpa INTO customer_number
WHERE vbeln = wk_document_number
AND parvw = 'AG'.
SELECT SINGLE kunnr FROM vbpa INTO distributor_number
WHERE vbeln = wk_document_number
AND parvw = 'ZE'.
I tried the following 2 variations to get the customer_number and distributor_number
Variant 1
SELECT VBELN PARVW KUNNR
FROM VBPA into TABLE IT_VBPA
WHERE VBELN = wk_document_number
and PARVW in ('AG', 'ZE').
LOOP at IT_VBPA into WA_VBPA.
CASE WA_VBPA-PARVW.
WHEN 'AG'.
customer_number = wa_vbpa-kunnr.
WHEN 'ZE'.
distributor_number = wa_vbpa-kunnr.
ENDCASE.
ENDLOOP.
Variant 2
SELECT PARVW KUNNR into (WA_VBPA-PARVW, WA_VBPA-KUNNR)
FROM VBPA
WHERE VBELN = wk_document_number
and PARVW in ('AG', 'ZE').
IF WA_VBPA-PARVW = 'AG'.
customer_number = wa_vbpa-kunnr.
ENDIF.
IF WA_VBPA-PARVW = 'ZE'.
distributor_number = wa_vbpa-kunnr.
ENDIF.
ENDSELECT.
I ran this test 10 times.
The Original code using 2 Select Single statements had the best performance. averaged about 278 ms
The Variant 1 code had the worst performance averaged about 308 ms
The Variant 2 code performance was nearly identical to the Original code averaged about 285 ms
Any thoughts on how to improve this. The average run times look low, but when there are 45000 records to process, they add up. For example, in the case of the original code, this would be about 208 minutes of processing time and if it was doing the code in Variant 2, it would take 231 minutes.
Thanks
2015 Jan 27 1:15 PM
Hi Bob,
I am trying to answer as per my understanding and assumption. I am assuming that your code is getting called many times for same document number.
If my assumption is right then may be you can build the logic to fetch data from VBPA and store in some variables or internal table when your code gets executed first time and then you can check this variables and if entries are exist in these variables then do not execute select statements and use the variable values.
Like this,
if customer_number is initial.
SELECT SINGLE kunnr FROM vbpa INTO customer_number
WHERE vbeln = wk_document_number
AND parvw = 'AG'.
endif.
if distributor_number is INITIAL.
SELECT SINGLE kunnr FROM vbpa INTO distributor_number
WHERE vbeln = wk_document_number
AND parvw = 'ZE'.
ENDIF.
may be you have to export customer_number and distributor_number to memory at first execution and IMPORT and use same on subsequent execution.
Let me know if this helps.
Regards,
Sid
2015 Jan 21 8:43 PM
You might try changing the first select to one based on VBAP, so long as KUNNR is always the actual customer number you want. This way the SELECT SINGLE will be able to use the complete index.
Rob
2015 Jan 22 3:04 PM
I added POSNR in the selects and the results are the same in all 3 variations of the Select statements
2015 Jan 22 3:05 PM
I added 'POSNR' in the selects and the results are the same in all 3 variations of the Select statements
2015 Jan 22 3:41 PM
Actually, I meant VBAK. See if this works:
SELECT SINGLE vbak~kunnr vbpa~kunnr
INTO (customer_number, partner_number)
FROM vbak
JOIN vbpa ON
vbpa~vbeln = vbak~vbeln
WHERE vbpa~parvw IN ('AG', 'ZE').
Rob
2015 Jan 22 2:15 AM
Hi, Bob,
I think there are some other process logic you must need call this FM, right?
So maybe you could create a global itab2 use to store VBPA data.
In FM:
SORT gt_itab2 BY vbeln.
READ gt_itab2 into wa_itab2 WITH KEY vbeln = wk_document_number BINARY SEARCHER.
IF SY-SUBRC NE 0.
clear_wa_itab2.
wa_itab2-vbeln = wk_document_number.
SELECT SINGLE kunnr FROM vbpa INTO customer_number
WHERE vbeln = wk_document_number
AND parvw = 'AG'.
wa_itab2-customer = customer_number.
SELECT SINGLE kunnr FROM vbpa INTO distributor_number
WHERE vbeln = wk_document_number
AND parvw = 'ZE'.
wa_itab2-distributor = distributor_number.
APPEND wa_itab2 TO gt_itab2.
ELSE.
customer_number = wa_itab2-customer.
distributor_number = wa_itab2-distributor.
ENDIF.
Hope can help you.
regards,
Archer
2015 Jan 22 2:19 AM
Hi,
You should use batch processing as below:
1. Get all related SO (r_vbeln) into interal table IT_VBPA that can read table only one time.
SELECT VBELN PARVW KUNNR
FROM VBPA into TABLE IT_VBPA
WHERE VBELN in r_vblen
and PARVW in ('AG', 'ZE').
2. In looping:
read table it_vbpa into wa_vbpa with key vbeln = l_vbeln PARVW = 'AG'.
customer_number = wa_vbpa-kunnr.
read table it_vbpa into wa_vbpa with key vbeln = l_vbeln PARVW = 'AE'.
distributor_number = wa_vbpa-kunnr.
Best regards,
Jimmy Chan
2015 Jan 22 4:51 PM
The big issue is that this code is in a pricing condition exit RV64xxxx, so it gets called several times for each line item.
2015 Jan 22 8:57 PM
The main program (that is calling the RV64xxxx ) should be saving all partner data in an internal table. IF it is not then you can build an internal table with all partner data and then read that internal table inside RV64xxxx. If required you can pass the internal table using export statement and then import it inside RV64xxxx. This way you can avoid using select statement inside RV64xxxx and improve performance.
2015 Jan 23 1:58 PM
Checked it out, but the code is being called from SAPLV61A forms XKOMV_KWERT_ERMITTELN and XKOMV_BEWERTEN. So, I cannot add code there. I think I will try to find an earlier user exit and Export to Memory
2015 Jan 23 4:40 AM
Hi,
U shall try the below code by avoiding LOOP.
SELECT VBELN PARVW KUNNR
FROM VBPA into TABLE IT_CUST
WHERE VBELN = wk_document_number
and PARVW in ('AG', 'ZE').
IT_DIST[] = IT_CUST[].
sort IT_DIST by ZE.
sort IT_CUST by AG.
Delete IT_DIST where PARVW ne 'ZE'.
Delete IT_CUST where PARVW ne 'AG'.
Regards,
Vinodkumar.
2015 Jan 23 10:11 PM
Hi Bob !
Have you tried using up to x rows with endselect?
Another way for you to improve your performance is to create cursors and put limits packages. The two ways reduced the query time x runtime.
Adding, you can put your declarations of internal table as hashed tables and use the primary keys to search.
BR,
Raphael
2015 Jan 27 1:15 PM
Hi Bob,
I am trying to answer as per my understanding and assumption. I am assuming that your code is getting called many times for same document number.
If my assumption is right then may be you can build the logic to fetch data from VBPA and store in some variables or internal table when your code gets executed first time and then you can check this variables and if entries are exist in these variables then do not execute select statements and use the variable values.
Like this,
if customer_number is initial.
SELECT SINGLE kunnr FROM vbpa INTO customer_number
WHERE vbeln = wk_document_number
AND parvw = 'AG'.
endif.
if distributor_number is INITIAL.
SELECT SINGLE kunnr FROM vbpa INTO distributor_number
WHERE vbeln = wk_document_number
AND parvw = 'ZE'.
ENDIF.
may be you have to export customer_number and distributor_number to memory at first execution and IMPORT and use same on subsequent execution.
Let me know if this helps.
Regards,
Sid
2015 Jan 30 4:11 PM
yes, I believe export to memory is the only way to handle this. Thanks
2015 Jan 30 3:25 PM