Des problemes de performance en ABAP Cloud ? Ces 10 Quick Wins apportent des ameliorations immediates - avec des exemples de code.
Etat d’esprit Performance
Regles d’or :
- Mesurer d’abord - Ne pas deviner, mesurer !
- DB > ABAP - Pousser le travail dans la base de donnees
- Batch > Loop - Regrouper les operations
- Cache intelligent - Mais ne pas sur-optimiser
1. Eviter SELECT sans WHERE
Mauvais (charge TOUT)
SELECT * FROM I_Customer INTO TABLE @DATA(lt_customers).
LOOP AT lt_customers INTO DATA(ls_customer) WHERE Country = 'DE'. " TraitementENDLOOP.Probleme : 1 million de lignes chargees, 950k rejetees !
Bon (WHERE en DB)
SELECT Customer, CustomerName, Country FROM I_Customer WHERE Country = 'DE" INTO TABLE @DATA(lt_customers).Acceleration : ~95% (sur 1 million de lignes)
2. Eviter SELECT dans les boucles
Mauvais (Probleme N+1)
LOOP AT lt_orders INTO DATA(ls_order). " ❌ SELECT par iteration! SELECT SINGLE CustomerName FROM I_Customer WHERE Customer = @ls_order-customer INTO @DATA(lv_name).ENDLOOP.Avec 1000 commandes : 1000 instructions SELECT !
Bon (FOR ALL ENTRIES)
" Un SELECT pour tousSELECT Customer, CustomerName FROM I_Customer FOR ALL ENTRIES IN @lt_orders WHERE Customer = @lt_orders-customer INTO TABLE @DATA(lt_customers).
" Jointure en memoireLOOP AT lt_orders ASSIGNING FIELD-SYMBOL(<order>). READ TABLE lt_customers INTO DATA(ls_cust) WITH KEY customer = <order>-customer. <order>-customer_name = ls_cust-customername.ENDLOOP.Acceleration : ~90% (1000 → 1 appel DB)
3. CDS Views au lieu de joins ABAP
Mauvais (Join en ABAP)
SELECT Customer, CustomerName FROM I_Customer INTO TABLE @DATA(lt_customers).
SELECT SalesOrder, Customer, NetValue FROM I_SalesOrder INTO TABLE @DATA(lt_orders).
" Join en ABAP ❌LOOP AT lt_orders ASSIGNING <order>. READ TABLE lt_customers INTO DATA(ls_cust) WITH KEY customer = <order>-customer. " ...ENDLOOP.Bon (Join en CDS)
define view Z_CustomerOrders as select from I_Customer inner join I_SalesOrder on I_Customer.Customer = I_SalesOrder.Customer{ key I_Customer.Customer, I_Customer.CustomerName, I_SalesOrder.SalesOrder, I_SalesOrder.NetValue}SELECT * FROM Z_CustomerOrders INTO TABLE @DATA(lt_result).Acceleration : ~80% (la DB fait le join plus efficacement)
4. Batching des operations EML
Mauvais (Boucle)
LOOP AT lt_book_ids INTO DATA(lv_id). " ❌ MODIFY par ID MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( ( BookId = lv_id Status = 'F' ) ).ENDLOOP.
COMMIT ENTITIES.Avec 100 livres : 100x acces DB !
Bon (Batch)
" Un MODIFY pour tousMODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( FOR lv_id IN lt_book_ids ( BookId = lv_id Status = 'F' ) ) FAILED DATA(failed).
COMMIT ENTITIES.Acceleration : ~85%
5. Projection au lieu de SELECT *
Mauvais (tous les champs)
SELECT * FROM I_Product INTO TABLE @DATA(lt_products).Charge 50 champs, mais n’en utilise que 3 !
Bon (uniquement les champs necessaires)
SELECT Product, ProductName, Price FROM I_Product INTO TABLE @DATA(lt_products).Acceleration : ~60% (moins de trafic reseau)
6. Activer le buffering des tables
Pour les donnees de reference (changent rarement) :
@AbapCatalog.buffering.status: #ACTIVE@AbapCatalog.buffering.type: #FULL@AbapCatalog.buffering.numberOfKeyFields: 1
define view Z_Country as select from T005{ key land1 as Country, landx as CountryName}Acceleration : ~95% (donnees depuis la memoire au lieu de la DB)
MAIS : Uniquement pour les donnees qui changent rarement !
7. FILTER au lieu de LOOP + IF
Mauvais
DATA lt_active_customers TYPE TABLE OF ty_customer.
LOOP AT lt_customers INTO DATA(ls_customer) WHERE status = 'ACTIVE'. APPEND ls_customer TO lt_active_customers.ENDLOOP.Bon (Expression FILTER)
DATA(lt_active) = FILTER #( lt_customers WHERE status = 'ACTIVE' ).Acceleration : ~30% (moins de code, optimise)
8. REDUCE au lieu de LOOP pour les agregations
Mauvais
DATA lv_total TYPE p.
LOOP AT lt_orders INTO DATA(ls_order). lv_total = lv_total + ls_order-amount.ENDLOOP.Bon (REDUCE)
DATA(lv_total) = REDUCE p( INIT sum = 0 FOR ls_order IN lt_orders NEXT sum = sum + ls_order-amount ).Acceleration : ~20%
9. Lazy Loading avec les Associations
Mauvais (tout charger)
define view Z_CustomerWithOrders as select from I_Customer left outer join I_SalesOrder on I_Customer.Customer = I_SalesOrder.Customer{ I_Customer.Customer, I_Customer.CustomerName, I_SalesOrder.SalesOrder, I_SalesOrder.NetValue}Probleme : Meme si les commandes ne sont pas necessaires, toujours un join !
Bon (Association)
define view Z_Customer as select from I_Customer association [0..*] to I_SalesOrder as _Orders on $projection.Customer = _Orders.Customer{ key Customer, CustomerName,
_Orders // Exposer seulement, pas de join!}Utilisation :
" Seulement CustomerSELECT Customer, CustomerName FROM Z_Customer INTO TABLE @DATA(lt_customers).
" Avec Orders (seulement si necessaire!)SELECT Customer, \_Orders-SalesOrder FROM Z_Customer INTO TABLE @DATA(lt_with_orders).Acceleration : ~70% (quand les commandes sont rarement necessaires)
10. Utiliser SQL Trace
Trouver les goulots d’etranglement :
Dans ADT :
Run→Run Configurations- Onglet
Trace Requests - Activer
SQL Trace - Executer le programme
Analyser :
❌ SELECT * FROM mara Duration: 2.5s Rows: 500,000
✅ SELECT matnr FROM mara WHERE mtart = 'FERT" Duration: 0.01s Rows: 1,000Action : Optimiser les SELECTs lents !
Checklist Performance
Revue de code
- Pas de
SELECT * - Clause WHERE utilise l’index
- Pas de SELECT dans LOOP
- EML en batch
- FOR ALL ENTRIES verifie table vide
- CDS Views pour les joins
- FILTER/REDUCE au lieu de LOOP
- Buffering pour les donnees de reference
Mesure
- SQL Trace effectue
- Performance < 1s pour les ops standard
- Pas de timeouts
- Consommation memoire acceptable
Benchmarks de performance
Exemple : 10 000 enregistrements
| Operation | Avant | Apres | Acceleration |
|---|---|---|---|
| SELECT * | 2,5s | 0,3s (seulement champs) | 88% |
| SELECT en boucle | 15,0s | 0,5s (FOR ALL ENTRIES) | 97% |
| LOOP + IF | 0,8s | 0,2s (FILTER) | 75% |
| Join ABAP | 3,0s | 0,4s (CDS) | 87% |
| Boucle EML | 5,0s | 0,6s (Batch) | 88% |
Total : De 26,3s a 2,0s = 92% d’acceleration !
Resume
Classement des Quick Wins :
- SELECT en boucle → FOR ALL ENTRIES (+90%)
- Batching EML (+85%)
- Utiliser clause WHERE (+95%)
- CDS Views pour les joins (+80%)
- Seulement les champs necessaires (+60%)
- Lazy Loading (+70%)
- FILTER/REDUCE (+20-30%)
- Buffering (+95% mais niche)
- SQL Trace (trouve les problemes)
- Projection Views (+60%)
Etat d’esprit : Utiliser la puissance de la DB, minimiser le travail ABAP !
Voir aussi :
Bonne optimisation !