Performance-Probleme in ABAP Cloud? Diese 10 Quick Wins bringen sofortige Verbesserungen - mit Code-Beispielen.
🎯 Performance Mindset
Golden Rules:
- Measure First - Nicht raten, messen!
- DB > ABAP - Arbeit in Datenbank pushen
- Batch > Loop - Operationen bündeln
- Cache Smart - Aber nicht überoptimieren
1. SELECT ohne WHERE vermeiden
❌ Schlecht (lädt ALLES)
SELECT * FROM I_Customer INTO TABLE @DATA(lt_customers).
LOOP AT lt_customers INTO DATA(ls_customer) WHERE Country = 'DE'. " VerarbeitungENDLOOP.Problem: 1 Mio Zeilen geladen, 950k verworfen!
✅ Gut (WHERE in DB)
SELECT Customer, CustomerName, Country FROM I_Customer WHERE Country = 'DE' INTO TABLE @DATA(lt_customers).Speedup: ~95% (bei 1 Mio Zeilen)
2. SELECT in Loops vermeiden
❌ Schlecht (N+1 Problem)
LOOP AT lt_orders INTO DATA(ls_order). " ❌ SELECT pro Iteration! SELECT SINGLE CustomerName FROM I_Customer WHERE Customer = @ls_order-customer INTO @DATA(lv_name).ENDLOOP.Bei 1000 Orders: 1000 SELECT-Statements!
✅ Gut (FOR ALL ENTRIES)
" Ein SELECT für alleSELECT Customer, CustomerName FROM I_Customer FOR ALL ENTRIES IN @lt_orders WHERE Customer = @lt_orders-customer INTO TABLE @DATA(lt_customers).
" In Memory joinenLOOP 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.Speedup: ~90% (1000 → 1 DB-Call)
3. CDS Views statt ABAP Joins
❌ Schlecht (Join in 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 in ABAP ❌LOOP AT lt_orders ASSIGNING <order>. READ TABLE lt_customers INTO DATA(ls_cust) WITH KEY customer = <order>-customer. " ...ENDLOOP.✅ Gut (Join in 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).Speedup: ~80% (DB macht Join effizienter)
4. EML-Operationen batchen
❌ Schlecht (Loop)
LOOP AT lt_book_ids INTO DATA(lv_id). " ❌ MODIFY pro ID MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( ( BookId = lv_id Status = 'F' ) ).ENDLOOP.
COMMIT ENTITIES.Bei 100 Büchern: 100× DB-Zugriff!
✅ Gut (Batch)
" Ein MODIFY für alleMODIFY 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.Speedup: ~85%
5. Projection statt SELECT *
❌ Schlecht (alle Felder)
SELECT * FROM I_Product INTO TABLE @DATA(lt_products).Lädt 50 Felder, nutzt aber nur 3!
✅ Gut (nur benötigte Felder)
SELECT Product, ProductName, Price FROM I_Product INTO TABLE @DATA(lt_products).Speedup: ~60% (weniger Netzwerk-Traffic)
6. Table Buffering aktivieren
Für Master-Daten (selten ändert sich):
@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}Speedup: ~95% (Daten aus Memory statt DB)
ABER: Nur für Daten die selten ändern!
7. FILTER statt LOOP + IF
❌ Schlecht
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.✅ Gut (FILTER Expression)
DATA(lt_active) = FILTER #( lt_customers WHERE status = 'ACTIVE' ).Speedup: ~30% (weniger Code, optimiert)
8. REDUCE statt LOOP für Aggregationen
❌ Schlecht
DATA lv_total TYPE p.
LOOP AT lt_orders INTO DATA(ls_order). lv_total = lv_total + ls_order-amount.ENDLOOP.✅ Gut (REDUCE)
DATA(lv_total) = REDUCE p( INIT sum = 0 FOR ls_order IN lt_orders NEXT sum = sum + ls_order-amount ).Speedup: ~20%
9. Lazy Loading mit Associations
❌ Schlecht (alles laden)
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}Problem: Auch wenn Orders nicht gebraucht werden, immer Join!
✅ Gut (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 // Nur exposen, kein Join!}Verwendung:
" Nur CustomerSELECT Customer, CustomerName FROM Z_Customer INTO TABLE @DATA(lt_customers).
" Mit Orders (nur wenn nötig!)SELECT Customer, \_Orders-SalesOrder FROM Z_Customer INTO TABLE @DATA(lt_with_orders).Speedup: ~70% (wenn Orders selten gebraucht)
10. SQL Trace nutzen
Bottlenecks finden:
In ADT:
Run→Run Configurations- Tab
Trace Requests SQL Traceaktivieren- Programm ausführen
Analysieren:
❌ SELECT * FROM mara Duration: 2.5s Rows: 500,000
✅ SELECT matnr FROM mara WHERE mtart = 'FERT' Duration: 0.01s Rows: 1,000Action: Langsame SELECTs optimieren!
Performance Checkliste
Code Review
- Kein
SELECT * - WHERE-Clause nutzt Index
- Kein SELECT in LOOP
- EML gebatcht
- FOR ALL ENTRIES prüft auf leere Tabelle
- CDS Views für Joins
- FILTER/REDUCE statt LOOP
- Buffering für Master-Daten
Measurement
- SQL Trace durchgeführt
- Performance < 1s für Standard-Ops
- Keine Timeouts
- Memory-Verbrauch akzeptabel
Performance-Benchmarks
Beispiel: 10.000 Datensätze
| Operation | Vorher | Nachher | Speedup |
|---|---|---|---|
| SELECT * | 2.5s | 0.3s (nur Felder) | 88% |
| SELECT in Loop | 15.0s | 0.5s (FOR ALL ENTRIES) | 97% |
| LOOP + IF | 0.8s | 0.2s (FILTER) | 75% |
| ABAP Join | 3.0s | 0.4s (CDS) | 87% |
| EML Loop | 5.0s | 0.6s (Batch) | 88% |
Gesamt: Von 26.3s auf 2.0s = 92% Speedup!
🎯 Zusammenfassung
Quick Win Ranking:
- ⭐⭐⭐ SELECT in Loop → FOR ALL ENTRIES (+90%)
- ⭐⭐⭐ EML Batching (+85%)
- ⭐⭐⭐ WHERE-Clause nutzen (+95%)
- ⭐⭐ CDS Views für Joins (+80%)
- ⭐⭐ Nur benötigte Felder (+60%)
- ⭐⭐ Lazy Loading (+70%)
- ⭐ FILTER/REDUCE (+20-30%)
- ⭐ Buffering (+95% aber niche)
- ⭐ SQL Trace (findet Probleme)
- ⭐ Projection Views (+60%)
Mindset: DB-Power nutzen, ABAP-Arbeit minimieren!
Siehe auch:
Happy Optimizing! 🚀