Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Performance Improvement
Technique
Applies to:
Release SAP 4.6B and greater.
Summary
Scenario: Existing application for many years ran successfully. It came to a point where this was no longer
possible due to the size of the database tables used in the program.
To achieve the running of a report to completion without having a time-out event occur, I found that it was
necessary to change the affected inner-join select to be converted into multiple RFC (remote function call)
contained function module calls. The design is to obtain the header level data first, then use this in multiple
smaller iterations in slice form for the select statement ‘for all entries’ clause.
Author Bio
Started technical career in 1982 at IBM as a mainframe Technician. Went to programming and
SAP ABAP Application Development in 1990 and 1994 timeframes respectively. Holds B.A. in
Computer Science- 1998.
Company: EDS – Electronic Data Systems.
Work: 100% travel contractor working in SAP ABAP Application Development, with focus on
performance tuning.
Table of Contents
Methodology Used:.............................................................................................................................................3
Analysis of Bottleneck in Original Program.....................................................................................................3
Development Environment Overview..............................................................................................................3
Performance Enhancements Accomplished: ..................................................................................................3
Other Performance Enhancements to Consider:............................................................................................4
Development overview diagram...................................................................................................................................5
Select Statement ‘For All Entries’ Slice Size ..................................................................................................5
Slice Size Scope and Automation...................................................................................................................6
RFC Function Module Logging Details ...........................................................................................................6
Some perFormance Numbers (Comparisons Done on Development System): ................................................7
Development and Debug Hints...........................................................................................................................8
External Parameters .......................................................................................................................................8
Debug..............................................................................................................................................................8
This is a Multi-Session Debugging Environment..........................................................................................................8
Anomaly ..........................................................................................................................................................9
Example Code:..............................................................................................................................................10
Main Program Selection Screen ...................................................................................................................10
Function Group .............................................................................................................................................13
Top include File from Function Group...........................................................................................................14
ZMSEG_MKPF_Select .................................................................................................................................15
ZMKPF_Select Function Module ..................................................................................................................22
ZMSEG_Select Function Module..................................................................................................................24
ZSplitDates_to_Table Function Module........................................................................................................26
Miscellaneous Structures ..............................................................................................................................29
ZMatnr_Range ...........................................................................................................................................................29
ZMSEG ......................................................................................................................................................................29
ZMKPF_T...................................................................................................................................................................30
ZDatum_Range..........................................................................................................................................................30
Related Content................................................................................................................................................31
Disclaimer and Liability Notice..........................................................................................................................32
Methodology Used:
• Perform many smaller select statements using smaller portions of the first extracted header level
data in RFC function modules, in order for each select to run concurrently in its own memory space
and system CPU process.
o The longer running select statement processes are viewable via transaction SM50 on a real-
time basis.
Large table to be
selected using small
Output data
table in an inner-join
Small Table
extracted select statement.
from header One table containing
level results data from the
For every row in the matching and combining
small table, find one or of rows from the two
tables.
more matching rows in
database table.
The above would work efficiently, unless the table sizes involved cause the program to time out.
The above design has approached the limitation of its usefulness in the program. For example, in QA1
the original select MKPF/MSEG inner-join would process approximately thirty six million header rows in
MKPF. From this, six million rows of MKPF data would be extracted for a typical program date range of
one month. This would be represented by the small table to the left above. This six million rows of MKPF
data would be used as to cross-reference to check against each row in the MSEG table. MSEG was
approximately one hundred and sixteen million rows in size (the middle box, above). The intention of the
design would be to ‘get in, and get out’, all in one database call, which minimizes the impact to the
database. With the number of rows that these tables contain, the processing of the data was not
impossible to do so in the time allotted. The result would be program time out conditions in QA1 and in
the production systems.
As in indexes, there is an optimal balance for each select statement, internal table, and for each SAP
system. As a starting reference, it is acknowledged that 9-10 processes is the goal achieve. In terms of
database parameters:
If the data selected is large enough, transaction SM50 can be used to display process running times and
table name for each RFC function module call.
Variant 1 – Jan 2, 2006 to Jan 31, 07 Variant 1 – Jan 2, 2006 to Jan 31, 07
Variant 2 – Jan 2, 2005 to Jan 31, 05 Variant 2 – Jan 2, 2005 to Jan 31, 05
Variants data used was the same, and program data output compared to be equal for both.
Debug
Write statements, or Pop-up to confirm type function modules in the ‘Performing xxFormxx at end of task’
forms do not execute.
Anomaly
Once in a while, it seems that the divide calculation adds one more to the result amount:
NumSteps_Gjahr – the number of steps for a given year, should be ‘1’ in the above program debug state.
If the above does occur, the code in this example is able to handle this without selecting repeating rows of
data. This is accomplished by: Extra iterations result in the x and y indexes incrementing past the point of the
main ‘for all entries’ table rows to select slices. In our example, this is it_mkpf_mjahr. In this case, the
statement:
• Append lines of it_mkpf_mjahr from indx to indy to it_mkpf_slice will be of no effect.
The other part of the built-in safeguard is that the table select RFC function module (in here, ZMSEG_Select)
will perform the select statement only if the ‘for all entries’ table contains at least one row.
The code for this does a preliminary check to see if the initially calculated NumSteps, multiplied by the slice
size, is less than the total number of rows of the internal table that is being sliced. If so, then the mod division
calculation is done.
Example Code:
This code is designed to retrieve an aggregated set MKPF and MSEG table data for multiple posting date
years.
The example code is simplified to focus only on the multiple RFC performance enhancement technique. It is
composed of:
• a main report type program
• a main RFC enabled function module
• two table-select RFC enabled function modules
• a utility function module
• various structures defined in the data dictionary.
<html>
<head>
<title>SDN – Report for RFC source code example</title>
<link rel="stylesheet" type="text/css" href="/sdn/css/csin.css" />
<link rel="stylesheet" type="text/css" href="/sdn/css/sdn.css" />
</head>
<body>
*&---------------------------------------------------------------------*
*& Report for RFC source code example
*&
*&---------------------------------------------------------------------*
*& Author: Daniel M. Perecky
*& Date : 11-12-2007
*&---------------------------------------------------------------------*
REPORT ZTEST0011.
Tables: Mseg, Mkpf.
.
Message Id 'SY' Type 'E' Number 003 with 'an appropriate' 'error' 'msg'.
WHEN 3. "No resources available at present
.
. " handle resource limitation error
.
Message Id 'SY' Type 'E' Number 003 with 'an appropriate' 'error' 'msg'.
EndCase.
*----------------------------------------------------------------------
Describe table It_Mseg Lines Lns.
Write: / 'It_Mseg table size retrieved:', Lns.
Exit.
*&---------------------------------------------------------------------*
*& Form Get_MSEG_MKPF_SELECT
*&---------------------------------------------------------------------*
* Author: Daniel Perecky
*&---------------------------------------------------------------------*
* Purpose: This is the form specified in the call RFC function module
* statement.
* Note: Once completed, program execution resumes after the wait
* statement condition is met, above.
*----------------------------------------------------------------------*
Form Get_MSEG_MKPF_SELECT Using Name.
Data: Lns Type i.
If Name = 'MSEG_MKPF_SELECT'.
Receive results from function 'ZMSEG_MKPF_SELECT'
Tables it_mseg = it_mseg.
Add 1 to MSEG_MKPF_SELECT_Flg. " When data is received, increment flag for wait,
above.
If Syst-Subrc = 0.
Describe table it_mseg lines lns.
Write: / 'Get_Mseg_Mkpf_Select returned:', Lns, 'Lines'.
Endif.
Endif.
EndForm.
</body>
Function Group
ZMSEG_MKPF_Select
Function module is RFC enabled, per the attributes tab:
<html>
<head>
<title>Function Module ZMSEG_MKPF_Select</title>
<link rel="stylesheet" type="text/css" href="/sdn/css/csin.css" />
<link rel="stylesheet" type="text/css" href="/sdn/css/sdn.css" />
</head>
<body>
FUNCTION ZMSEG_MKPF_SELECT.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(P_SPOST) TYPE BUDAT
*" VALUE(P_EPOST) TYPE BUDAT
*" VALUE(P_TBLSLICE) TYPE SU_BSEG DEFAULT 250
*" TABLES
*" S_MATNR STRUCTURE ZMATNR_RANGE
*" IT_MSEG STRUCTURE ZMSEG
*"----------------------------------------------------------------------
* Date: 11/14/07 *
* Author: D Perecky *
* Title: RFC Function module code example. Main function module *
*----------------------------------------------------------------------*
* Change History: *
* Author Date Request# Description *
* ---------------------------------------------------------------------*
*+--------------------------------------------------------------------+*
*| Start of Selection |*
*+--------------------------------------------------------------------+*
Clear: it_mseg, it_mkpf_mjahr, it_Mkpf_Slice, DtRnge, CurrMjahr,
Numsteps_Gjahr, Numsteps_Total.
MKPF_Select_Flg = 0.
* Need to select bkpf bsim data by 1 year at a time: large table size.
* Bkpf size on QA- Unknown. always times out using 'num of rows'.
AddPrevious = 1.
CurrMjahr = DtRnge-Low+0(4).
* If we are looking for older data, make sure that it exists.
If CurrMjahr <= 2005.
Select Single Mjahr from MKPF
Into MKPF-Mjahr
Where Mjahr = CurrMjahr.
If Syst-Subrc = 4.
AddPrevious = 0.
Endif.
Endif.
If AddPrevious = 1 or CurrMjahr > 2005.
When Others.
" Handle other RFC failure.
Endcase.
*---------------------------------------------------------------
If MKPF_RC = 0. " Any data for this MjahrLoop year?
*---------------------------------------------------------------
Numsteps_Gjahr = 0.
i_TblSlice = p_TblSlice.
numsteps_n = Numsteps_Gjahr.
* Start Do loop.
Do Numsteps_Gjahr times.
When 0.
Append <fs> to T_Tasks.
Add 1 to n_loop. " For next loop.
When 1 or 2.
Message id 'SY' Type 'E' Number '002' with Msg.
When 3. " insufficient resources- wait to see if they free up
Wait Until n_task => n_loop up to 298 seconds. " max is 5 min.
If Syst-Subrc = 0.
Add 1 to n_loop. " For next loop.
Else.
Concatenate 'SAP Resource Failure, RFC Dest: ' rfc_Dest
into Syst-lisel.
Message id 'SY' Type 'E' Number '002' with Syst-Lisel.
Endif.
When Others.
N_subrc = Syst-Subrc.
Concatenate 'Other RFC Failure, Syst-Subrc: ' n_subrc
into Syst-lisel.
Message id 'SY' Type 'E' Number '002' with Syst-Lisel.
Endcase.
Refresh it_Mkpf_slice.
Indx = Indx + i_TblSlice. " Increment start index.
Indy = Indy + i_TblSlice. " Increment end index.
Wait Until n_task => NumSteps_Total. "no explicit limit: can be up to 298 seconds.
"Wait statement only works in Asynchronous RFC
* Continue looking for data until table t_Tasks is empty.
* Done with RFC select loop. Combine table fields for program.
It_Mseg[] = It_Mseg_Stg[].
Refresh: It_Mseg_Stg.
Free: It_Mseg_Stg. "free for performance
it_Mkpf[] = it_Mkpf_Stg[].
Refresh: it_Mkpf_Stg.
Free: it_Mkpf_Stg. "free for performance
SORT: it_mseg BY mjahr mblnr, it_Mkpf by mjahr mblnr.
ENDFUNCTION.
*&---------------------------------------------------------------------*
*& Form Get_RFC_MKPF
* Purpose: Data retrieval from RFC function module.
*&---------------------------------------------------------------------*
* Author: Daniel M. Perecky
*----------------------------------------------------------------------*
Form Get_RFC_MKPF Using Name.
If Name+0(7) = 'MKPFSLC'.
Receive results from function 'ZMKPF_SELECT'
Tables IT_MKPF = it_mkpf_mjahr.
Add 1 to MKPF_Select_Flg.
Endif.
EndForm. "Get_RFC_MKPF
*---------------------------------------------------------------------*
* Form Gather_Mseg_Info *
* Purpose: Data retrieval from RFC function module.
*&--------------------------------------------------------------------*
* Author: Daniel M. Perecky
*---------------------------------------------------------------------*
Form Get_RFC_MSEG Using Name Type C.
Data: Lns Type I.
<html>
<head>
<title>ZMSEG_Select</title>
<link rel="stylesheet" type="text/css" href="/sdn/css/csin.css" />
<link rel="stylesheet" type="text/css" href="/sdn/css/sdn.css" />
</head>
<body>
FUNCTION ZMSEG_SELECT.
*"----------------------------------------------------------------------
*"Local Interface:
*" TABLES
*" IT_MKPF_SLICE STRUCTURE ZMKPF_T
*" IT_MSEG STRUCTURE ZMSEG
*" IT_MATNR STRUCTURE ZMATNR_RANGE
*"----------------------------------------------------------------------
Data: MKPF_Slice_Lns Type I.
Describe table it_Mkpf_Slice Lines MKPF_Slice_Lns.
If Mkpf_Slice_Lns > 0.
SELECT mblnr
mjahr
zeile " item
bwart
matnr
werks
lgort
Into TABLE it_mseg
FROM mseg
For all entries in it_Mkpf_Slice
WHERE
mblnr = it_Mkpf_Slice-mblnr and
mjahr = it_Mkpf_Slice-mjahr and
matnr in it_matnr and
sobkz EQ space.
Write: / 'ZMSEG_Select Subrc:', Syst-Subrc, '/ lines:', Syst-DBCnt.
Endif.
ENDFUNCTION.
</body>
<html>
<head>
<title>ZSplitDates_to_Table source code</title>
<link rel="stylesheet" type="text/css" href="/sdn/css/csin.css" />
<link rel="stylesheet" type="text/css" href="/sdn/css/sdn.css" />
</head>
<body>
FUNCTION ZSPLITDATES_TO_TABLE.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(P_SPOST) TYPE BUDAT
*" VALUE(P_EPOST) TYPE BUDAT
*" TABLES
*" T_DATE_RANGE STRUCTURE ZDATUM_RANGE
*"----------------------------------------------------------------------
*" Purpose: Take a range of post dates- BUDAT, and break up in yearly
* increments into separate table rows.
*"----------------------------------------------------------------------
*" Author: Daniel M. Perecky 11-14-07
*"----------------------------------------------------------------------
Data: NumYears Type I.
Data: P_SPostMjahr(4) Type C,
P_EPostMjahr(4) Type C,
CurrMjahr Type I,
CurrMjahr_N(4) Type N.
If NumYears = 1.
T_DATE_RANGE-Sign = 'I'. T_DATE_RANGE-Option = 'BT'.
T_DATE_RANGE-Low = P_Spost. T_DATE_RANGE-High = P_EPost.
Append T_Date_Range.
*----------------------------------------------------------------
ElseIf NumYears = 2.
* Get year range
P_SPostMjahr = P_Spost+0(4).
P_EPostMjahr = P_EPost+0(4).
* Start Year
T_DATE_RANGE-Sign = 'I'. T_DATE_RANGE-Option = 'BT'.
T_DATE_RANGE-Low = P_SPost.
Concatenate P_SPostMjahr '1231' into T_DATE_RANGE-High.
Append T_Date_Range.
* End Year
T_DATE_RANGE-Sign = 'I'. T_DATE_RANGE-Option = 'BT'.
Concatenate P_EPostMjahr '0101' into T_DATE_RANGE-Low.
T_DATE_RANGE-High = P_EPost.
Append T_Date_Range.
*----------------------------------------------------------------
ElseIf NumYears > 2.
YrCtr = 1.
* Get year range
P_SPostMjahr = P_Spost+0(4).
P_EPostMjahr = P_EPost+0(4).
CurrMjahr = P_SPostMjahr.
Do NumYears Times.
If YrCtr = 1.
* Start Year
T_DATE_RANGE-Sign = 'I'. T_DATE_RANGE-Option = 'BT'.
T_DATE_RANGE-Low = P_SPost.
Concatenate P_SPostMjahr '1231' into T_DATE_RANGE-High.
Append T_Date_Range.
Endif.
If YrCtr = NumYears.
* End Year
T_DATE_RANGE-Sign = 'I'. T_DATE_RANGE-Option = 'BT'.
Concatenate P_EPostMjahr '0101' into T_DATE_RANGE-Low.
T_DATE_RANGE-High = P_EPost.
Append T_Date_Range.
Endif.
Add 1 to YrCtr.
Add 1 to CurrMjahr.
EndDo.
Endif.
ENDFUNCTION.
</body>
Miscellaneous Structures
ZMatnr_Range
ZMSEG
ZMKPF_T
ZDatum_Range
Related Content
Calling RFC Function Modules locally