Performance-Optimierung ist entscheidend für benutzerfreundliche und ressourcenschonende ABAP-Programme. Dieser Artikel zeigt die wichtigsten Techniken zur Leistungssteigerung.
Performance-Analyse-Tools
Tool
Transaktion
Beschreibung
SQL Trace
ST05
Datenbankzugriffe analysieren
ABAP Trace
SAT
Laufzeitanalyse
Code Inspector
SCI
Statische Codeanalyse
ABAP Profiler
SAT
Detaillierte Profilerstellung
Explain Plan
ST05
SQL-Ausführungsplan
SQL-Optimierung
Nur benötigte Spalten lesen
" Schlecht - alle Spalten lesen
SELECT*FROM mara INTO TABLE @DATA(lt_mara)
WHERE mtart ='FERT'.
" Gut - nur benötigte Spalten
SELECT matnr, maktx, mtart, matkl
FROM mara
INTO TABLE @DATA(lt_mara_opt)
WHERE mtart ='FERT'.
SELECT mit Index nutzen
" Schlecht - kein Index nutzbar
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr.
" Gut - Primärindex nutzen
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE vbeln = @lv_vbeln
AND posnr = @lv_posnr.
" Gut - Sekundärindex nutzen (wenn vorhanden)
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr
%_HINTSORACLE'INDEX(VBAP VBAP~Z01)'.
FOR ALL ENTRIES richtig nutzen
" Prüfung auf leere Tabelle ist PFLICHT!
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 statt 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).
Aggregatfunktionen nutzen
" Schlecht - alle Daten lesen und summieren
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 ).
" Gut - Datenbank summiert
SELECTSUM( kwmeng ) AS total
FROM vbap
WHERE vbeln = @lv_vbeln
INTO @DATA(lv_sum_db).
Pufferung aktivieren
" Tabellenpufferung in SE11 aktivieren:
" - Vollständige Pufferung (kleine Tabellen)
" - Generische Pufferung (Teil der Schlüsselfelder)
" - Einzelsatzpufferung
" Puffer umgehen bei Bedarf
SELECTSINGLE*FROM t001 BYPASSINGBUFFER
INTO @DATA(ls_t001)
WHERE bukrs = @lv_bukrs.
Bulk-Operationen
" Schlecht - einzelne INSERTs
LOOP AT lt_new_data INTODATA(ls_data).
INSERT ztable FROM ls_data.
ENDLOOP.
" Gut - Array INSERT
INSERT ztable FROM TABLE lt_new_data.
" Gut - Array UPDATE
UPDATE ztable FROM TABLE lt_update_data.
" Gut - Array DELETE
DELETE ztable FROM TABLE lt_delete_data.
Interne Tabellen
Richtige Tabellenart wählen
" STANDARD TABLE - sequentieller Zugriff, APPEND
DATA: lt_standard TYPE STANDARD TABLE OF sflight.
" SORTED TABLE - binäre Suche, sortierter Zugriff
DATA: lt_sorted TYPE SORTED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
" HASHED TABLE - direkter Schlüsselzugriff
DATA: lt_hashed TYPE HASHED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
READ TABLE optimieren
" Schlecht - lineare Suche
READ TABLE lt_standard INTODATA(ls_line)
WITH KEY carrid ='LH'.
" Gut - binäre Suche (Tabelle muss sortiert sein!)
SORT lt_standard BY carrid.
READ TABLE lt_standard INTO ls_line
WITH KEY carrid ='LH'BINARYSEARCH.
" Gut - SORTED oder HASHED TABLE
READ TABLE lt_sorted INTO ls_line
WITH TABLE KEY carrid ='LH' connid ='0400' fldate ='20250115'.
Sekundärschlüssel nutzen
" Sekundärschlüssel definieren
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.
" Zugriff über Sekundärschlüssel
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-Optimierung
" Schlecht - WHERE ohne Index
LOOP AT lt_large_table INTODATA(ls_line)
WHERE status ='A'.
ENDLOOP.
" Gut - WHERE auf sortierte Tabelle
LOOP AT lt_sorted INTO ls_line
WHERE carrid ='LH'. " Nutzt Sortierung
ENDLOOP.
" Gut - ASSIGNING statt INTO (keine Kopie)
LOOP AT lt_table ASSIGNINGFIELD-SYMBOL(<ls_line>).
<ls_line>-status ='P'. " Direkte Änderung
ENDLOOP.
" Gut - REFERENCE INTO für Leseoperationen
LOOP AT lt_table REFERENCEINTODATA(lr_line).
DATA(lv_value) = lr_line->field.
ENDLOOP.
Tabellen-Joins im Speicher
" Schlecht - verschachtelte LOOPs
LOOP AT lt_orders INTODATA(ls_order).
LOOP AT lt_items INTODATA(ls_item)
WHERE order_id = ls_order-order_id.
ENDLOOP.
ENDLOOP.
" Gut - SORTED TABLE mit 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.
Parallelisierung
Parallele RFC-Aufrufe
DATA: lv_task TYPE string,
lv_counter TYPE i,
lt_results TYPE TABLE OF ty_result.
" Parallele Tasks starten
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: synchron verarbeiten
CALLFUNCTION'Z_PROCESS_PACKAGE'
EXPORTING
is_package = ls_package
IMPORTING
es_result =DATA(ls_result).
APPEND ls_result TO lt_results.
ENDIF.
ENDLOOP.
" Auf alle Tasks warten
WAITUNTIL lv_completed = lv_counter UP TO300SECONDS.
" Callback-Methode
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 für parallele Verarbeitung
DATA: lt_input TYPE spta_t_input,
lt_output TYPE spta_t_output.
" Input vorbereiten
LOOP AT lt_work_items INTODATA(ls_item).
APPENDINITIAL LINE TO lt_input ASSIGNINGFIELD-SYMBOL(<ls_input>).
<ls_input>-data = ls_item.
ENDLOOP.
" Parallel verarbeiten
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-Operationen
Effiziente Verkettung
" Schlecht - wiederholte CONCATENATE
DATA: lv_result TYPE string.
LOOP AT lt_parts INTODATA(lv_part).
CONCATENATE lv_result lv_part INTO lv_result.
ENDLOOP.
" Gut - String Templates
lv_result =REDUCE string( INIT r =``
FORpartIN lt_parts
NEXT r = r &&part ).
" Gut - CONCATENATE LINES OF
CONCATENATELINES OF lt_parts INTO lv_result SEPARATEDBYspace.
Reguläre Ausdrücke cachen
" Schlecht - Regex bei jedem Aufruf neu kompilieren