Performance optimization is crucial for user-friendly and resource-efficient ABAP programs. This article shows the most important techniques for improving performance.
Performance Analysis Tools
Tool
Transaction
Description
SQL Trace
ST05
Analyze database accesses
ABAP Trace
SAT
Runtime analysis
Code Inspector
SCI
Static code analysis
ABAP Profiler
SAT
Detailed profiling
Explain Plan
ST05
SQL execution plan
SQL Optimization
Only Read Required Columns
" Bad - read all columns
SELECT*FROM mara INTO TABLE @DATA(lt_mara)
WHERE mtart ='FERT'.
" Good - only required columns
SELECT matnr, maktx, mtart, matkl
FROM mara
INTO TABLE @DATA(lt_mara_opt)
WHERE mtart ='FERT'.
SELECT with Index Usage
" Bad - no index usable
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr.
" Good - use primary index
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE vbeln = @lv_vbeln
AND posnr = @lv_posnr.
" Good - use secondary index (if available)
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr
%_HINTSORACLE'INDEX(VBAP VBAP~Z01)'.
Use FOR ALL ENTRIES Correctly
" Check for empty table is MANDATORY!
IF lt_orders ISNOTINITIAL.
SELECT vbeln, posnr, matnr, kwmeng
FROM vbap
FORALLENTRIESIN @lt_orders
WHERE vbeln = @lt_orders-vbeln
INTO TABLE @DATA(lt_items).
ENDIF.
" Alternative: JOIN instead of FOR ALL ENTRIES
SELECT v~vbeln, v~posnr, v~matnr, v~kwmeng
FROM vbap AS v
INNERJOIN @lt_orders ASo ON v~vbeln = o~vbeln
INTO TABLE @DATA(lt_items_join).
Use Aggregate Functions
" Bad - read all data and sum
SELECT*FROM vbap INTO TABLE @DATA(lt_all)
WHERE vbeln = @lv_vbeln.
DATA(lv_sum) =REDUCE kwmeng( INITsum=0
FOR wa IN lt_all
NEXTsum=sum+ wa-kwmeng ).
" Good - database sums
SELECTSUM( kwmeng ) AS total
FROM vbap
WHERE vbeln = @lv_vbeln
INTO @DATA(lv_sum_db).
Enable Buffering
" Enable table buffering in SE11:
" - Full buffering (small tables)
" - Generic buffering (part of key fields)
" - Single record buffering
" Bypass buffer when needed
SELECTSINGLE*FROM t001 BYPASSINGBUFFER
INTO @DATA(ls_t001)
WHERE bukrs = @lv_bukrs.
Bulk Operations
" Bad - individual INSERTs
LOOP AT lt_new_data INTODATA(ls_data).
INSERT ztable FROM ls_data.
ENDLOOP.
" Good - array INSERT
INSERT ztable FROM TABLE lt_new_data.
" Good - array UPDATE
UPDATE ztable FROM TABLE lt_update_data.
" Good - array DELETE
DELETE ztable FROM TABLE lt_delete_data.
Internal Tables
Choose the Right Table Type
" STANDARD TABLE - sequential access, APPEND
DATA: lt_standard TYPE STANDARD TABLE OF sflight.
" SORTED TABLE - binary search, sorted access
DATA: lt_sorted TYPE SORTED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
" HASHED TABLE - direct key access
DATA: lt_hashed TYPE HASHED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
Optimize READ TABLE
" Bad - linear search
READ TABLE lt_standard INTODATA(ls_line)
WITH KEY carrid ='LH'.
" Good - binary search (table must be sorted!)
SORT lt_standard BY carrid.
READ TABLE lt_standard INTO ls_line
WITH KEY carrid ='LH'BINARYSEARCH.
" Good - SORTED or HASHED TABLE
READ TABLE lt_sorted INTO ls_line
WITH TABLE KEY carrid ='LH' connid ='0400' fldate ='20250115'.
Use Secondary Keys
" Define secondary key
DATA: lt_flights TYPE SORTED TABLE OF sflight
WITH UNIQUE KEY primary_key COMPONENTS carrid connid fldate
WITH NON-UNIQUE SORTED KEY by_plane COMPONENTS planetype.
" Access via secondary key
READ TABLE lt_flights INTODATA(ls_flight)
WITH KEY by_plane COMPONENTS planetype ='A380'.
LOOP AT lt_flights INTO ls_flight USING KEY by_plane
WHERE planetype ='A380'.
ENDLOOP.
LOOP Optimization
" Bad - WHERE without index
LOOP AT lt_large_table INTODATA(ls_line)
WHERE status ='A'.
ENDLOOP.
" Good - WHERE on sorted table
LOOP AT lt_sorted INTO ls_line
WHERE carrid ='LH'. " Uses sorting
ENDLOOP.
" Good - ASSIGNING instead of INTO (no copy)
LOOP AT lt_table ASSIGNINGFIELD-SYMBOL(<ls_line>).
<ls_line>-status ='P'. " Direct modification
ENDLOOP.
" Good - REFERENCE INTO for read operations
LOOP AT lt_table REFERENCEINTODATA(lr_line).
DATA(lv_value) = lr_line->field.
ENDLOOP.
Table Joins in Memory
" Bad - nested LOOPs
LOOP AT lt_orders INTODATA(ls_order).
LOOP AT lt_items INTODATA(ls_item)
WHERE order_id = ls_order-order_id.
ENDLOOP.
ENDLOOP.
" Good - SORTED TABLE with WHERE
DATA: lt_items_sorted TYPE SORTED TABLE OF ty_item
WITH NON-UNIQUE KEY order_id.
lt_items_sorted = lt_items.
LOOP AT lt_orders INTO ls_order.
LOOP AT lt_items_sorted INTO ls_item
WHERE order_id = ls_order-order_id.
ENDLOOP.
ENDLOOP.
Parallelization
Parallel RFC Calls
DATA: lv_task TYPE string,
lv_counter TYPE i,
lt_results TYPE TABLE OF ty_result.
" Start parallel tasks
LOOP AT lt_work_packages INTODATA(ls_package).
lv_counter = lv_counter +1.
lv_task =|TASK{ lv_counter }|.
CALLFUNCTION'Z_PROCESS_PACKAGE'
STARTINGNEWTASK lv_task
DESTINATIONINGROUP DEFAULT
CALLING on_task_complete ONEND OFTASK
EXPORTING
is_package = ls_package
EXCEPTIONS
resource_failure =1
communication_failure =2.
IFsy-subrc<>0.
" Fallback: process synchronously
CALLFUNCTION'Z_PROCESS_PACKAGE'
EXPORTING
is_package = ls_package
IMPORTING
es_result =DATA(ls_result).
APPEND ls_result TO lt_results.
ENDIF.
ENDLOOP.
" Wait for all tasks
WAITUNTIL lv_completed = lv_counter UP TO300SECONDS.
" Callback method
FORM on_task_complete USING p_task TYPE clike.
DATA: ls_result TYPE ty_result.
RECEIVERESULTSFROMFUNCTION'Z_PROCESS_PACKAGE'
IMPORTING
es_result = ls_result.
APPEND ls_result TO lt_results.
lv_completed = lv_completed +1.
ENDFORM.
SPTA Framework
" SPTA for parallel processing
DATA: lt_input TYPE spta_t_input,
lt_output TYPE spta_t_output.
" Prepare input
LOOP AT lt_work_items INTODATA(ls_item).
APPENDINITIAL LINE TO lt_input ASSIGNINGFIELD-SYMBOL(<ls_input>).
<ls_input>-data = ls_item.
ENDLOOP.
" Process in parallel
CALLFUNCTION'SPTA_PARA_PROCESS_START_2'
EXPORTING
server_group ='parallel_generators'
max_no_of_tasks =10
before_rfc_callback ='PREPARE_PACKAGE'
in_rfc_callback ='PROCESS_PACKAGE'
after_rfc_callback ='COLLECT_RESULT'
CHANGING
user_param = lt_input
EXCEPTIONS
OTHERS=1.
String Operations
Efficient Concatenation
" Bad - repeated CONCATENATE
DATA: lv_result TYPE string.
LOOP AT lt_parts INTODATA(lv_part).
CONCATENATE lv_result lv_part INTO lv_result.
ENDLOOP.
" Good - String Templates
lv_result =REDUCE string( INIT r =``
FORpartIN lt_parts
NEXT r = r &&part ).
" Good - CONCATENATE LINES OF
CONCATENATELINES OF lt_parts INTO lv_result SEPARATEDBYspace.