L’optimisation des performances est cruciale pour des programmes ABAP conviviaux et economes en ressources. Cet article presente les techniques les plus importantes pour ameliorer les performances.
Outils d’analyse des performances
Outil
Transaction
Description
SQL Trace
ST05
Analyser les acces a la base de donnees
ABAP Trace
SAT
Analyse du temps d’execution
Code Inspector
SCI
Analyse statique du code
ABAP Profiler
SAT
Profilage detaille
Explain Plan
ST05
Plan d’execution SQL
Optimisation SQL
Lire uniquement les colonnes necessaires
" Mauvais - lire toutes les colonnes
SELECT*FROM mara INTO TABLE @DATA(lt_mara)
WHERE mtart ='FERT'.
" Bon - uniquement les colonnes necessaires
SELECT matnr, maktx, mtart, matkl
FROM mara
INTO TABLE @DATA(lt_mara_opt)
WHERE mtart ='FERT'.
Utiliser les index avec SELECT
" Mauvais - pas d'index utilisable
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr.
" Bon - utiliser l'index primaire
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE vbeln = @lv_vbeln
AND posnr = @lv_posnr.
" Bon - utiliser un index secondaire (si disponible)
SELECT*FROM vbap INTO TABLE @DATA(lt_vbap)
WHERE matnr = @lv_matnr
%_HINTSORACLE'INDEX(VBAP VBAP~Z01)'.
Utiliser correctement FOR ALL ENTRIES
" La verification de table vide est OBLIGATOIRE !
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 au lieu de 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).
Utiliser les fonctions d’agregation
" Mauvais - lire toutes les donnees et faire la somme
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 ).
" Bon - la base de donnees fait la somme
SELECTSUM( kwmeng ) AS total
FROM vbap
WHERE vbeln = @lv_vbeln
INTO @DATA(lv_sum_db).
Activer la mise en buffer
" Activer la mise en buffer de table dans SE11 :
" - Mise en buffer complete (petites tables)
" - Mise en buffer generique (partie des champs cles)
" - Mise en buffer par enregistrement
" Contourner le buffer si necessaire
SELECTSINGLE*FROM t001 BYPASSINGBUFFER
INTO @DATA(ls_t001)
WHERE bukrs = @lv_bukrs.
Operations en masse
" Mauvais - INSERTs individuels
LOOP AT lt_new_data INTODATA(ls_data).
INSERT ztable FROM ls_data.
ENDLOOP.
" Bon - INSERT tableau
INSERT ztable FROM TABLE lt_new_data.
" Bon - UPDATE tableau
UPDATE ztable FROM TABLE lt_update_data.
" Bon - DELETE tableau
DELETE ztable FROM TABLE lt_delete_data.
Tables internes
Choisir le bon type de table
" STANDARD TABLE - acces sequentiel, APPEND
DATA: lt_standard TYPE STANDARD TABLE OF sflight.
" SORTED TABLE - recherche binaire, acces trie
DATA: lt_sorted TYPE SORTED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
" HASHED TABLE - acces direct par cle
DATA: lt_hashed TYPE HASHED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
Optimiser READ TABLE
" Mauvais - recherche lineaire
READ TABLE lt_standard INTODATA(ls_line)
WITH KEY carrid ='LH'.
" Bon - recherche binaire (la table doit etre triee !)
SORT lt_standard BY carrid.
READ TABLE lt_standard INTO ls_line
WITH KEY carrid ='LH'BINARYSEARCH.
" Bon - TABLE SORTED ou HASHED
READ TABLE lt_sorted INTO ls_line
WITH TABLE KEY carrid ='LH' connid ='0400' fldate ='20250115'.
Utiliser les cles secondaires
" Definir une cle secondaire
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.
" Acces via la cle secondaire
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.
Optimisation LOOP
" Mauvais - WHERE sans index
LOOP AT lt_large_table INTODATA(ls_line)
WHERE status ='A'.
ENDLOOP.
" Bon - WHERE sur table triee
LOOP AT lt_sorted INTO ls_line
WHERE carrid ='LH'. " Utilise le tri
ENDLOOP.
" Bon - ASSIGNING au lieu de INTO (pas de copie)
LOOP AT lt_table ASSIGNINGFIELD-SYMBOL(<ls_line>).
<ls_line>-status ='P'. " Modification directe
ENDLOOP.
" Bon - REFERENCE INTO pour les operations de lecture
LOOP AT lt_table REFERENCEINTODATA(lr_line).
DATA(lv_value) = lr_line->field.
ENDLOOP.
Jointures de tables en memoire
" Mauvais - LOOPs imbriques
LOOP AT lt_orders INTODATA(ls_order).
LOOP AT lt_items INTODATA(ls_item)
WHERE order_id = ls_order-order_id.
ENDLOOP.
ENDLOOP.
" Bon - SORTED TABLE avec 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.
Parallelisation
Appels RFC paralleles
DATA: lv_task TYPE string,
lv_counter TYPE i,
lt_results TYPE TABLE OF ty_result.
" Demarrer des taches paralleles
LOOP AT lt_work_packages INTODATA(ls_package).
lv_counter = lv_counter +1.
lv_task =|TASK{ lv_counter }|.
CALLFUNCTION'Z_PROCESS_PACKAGE"
STARTING NEW TASK lv_task
DESTINATION IN GROUP DEFAULT
CALLING on_task_complete ON END OF TASK
EXPORTING
is_package = ls_package
EXCEPTIONS
resource_failure = 1
communication_failure = 2.
IF sy-subrc <> 0.
" Fallback : traiter de maniere synchrone
CALL FUNCTION 'Z_PROCESS_PACKAGE"
EXPORTING
is_package = ls_package
IMPORTING
es_result =DATA(ls_result).
APPEND ls_result TO lt_results.
ENDIF.
ENDLOOP.
" Attendre toutes les taches
WAITUNTIL lv_completed = lv_counter UP TO300SECONDS.
" Methode de callback
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.
Framework SPTA
" SPTA pour le traitement parallele
DATA: lt_input TYPE spta_t_input,
lt_output TYPE spta_t_output.
" Preparer l'entree
LOOP AT lt_work_items INTODATA(ls_item).
APPENDINITIAL LINE TO lt_input ASSIGNINGFIELD-SYMBOL(<ls_input>).
<ls_input>-data = ls_item.
ENDLOOP.
" Traiter en parallele
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.
Operations sur les chaines
Concatenation efficace
" Mauvais - CONCATENATE repete
DATA: lv_result TYPE string.
LOOP AT lt_parts INTODATA(lv_part).
CONCATENATE lv_result lv_part INTO lv_result.
ENDLOOP.
" Bon - String Templates
lv_result =REDUCE string( INIT r =``
FORpartIN lt_parts
NEXT r = r &&part ).
" Bon - CONCATENATE LINES OF
CONCATENATELINES OF lt_parts INTO lv_result SEPARATEDBYspace.