¿Problemas de rendimiento en ABAP Cloud? Estos 10 Quick Wins traen mejoras inmediatas - con ejemplos de código.
Mentalidad de rendimiento
Reglas de oro:
- Medir primero - ¡No adivinar, medir!
- DB > ABAP - Empujar trabajo a la base de datos
- Batch > Loop - Agrupar operaciones
- Cache inteligente - Pero no sobreoptimizar
1. Evitar SELECT sin WHERE
❌ Malo (carga TODO)
SELECT * FROM I_Customer INTO TABLE @DATA(lt_customers).
LOOP AT lt_customers INTO DATA(ls_customer) WHERE Country = 'DE'. " ProcesamientoENDLOOP.Problema: ¡1 millón de filas cargadas, 950k descartadas!
✅ Bueno (WHERE en DB)
SELECT Customer, CustomerName, Country FROM I_Customer WHERE Country = 'DE' INTO TABLE @DATA(lt_customers).Speedup: ~95% (con 1 millón de filas)
2. Evitar SELECT en Loops
❌ Malo (Problema N+1)
LOOP AT lt_orders INTO DATA(ls_order). " ❌ SELECT por iteración! SELECT SINGLE CustomerName FROM I_Customer WHERE Customer = @ls_order-customer INTO @DATA(lv_name).ENDLOOP.¡Con 1000 pedidos: 1000 sentencias SELECT!
✅ Bueno (FOR ALL ENTRIES)
" Un SELECT para todosSELECT Customer, CustomerName FROM I_Customer FOR ALL ENTRIES IN @lt_orders WHERE Customer = @lt_orders-customer INTO TABLE @DATA(lt_customers).
" Join en memoriaLOOP 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 llamada DB)
3. CDS Views en lugar de Joins ABAP
❌ Malo (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.✅ Bueno (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).Speedup: ~80% (DB hace join más eficientemente)
4. Agrupar operaciones EML
❌ Malo (Loop)
LOOP AT lt_book_ids INTO DATA(lv_id). " ❌ MODIFY por ID MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( ( BookId = lv_id Status = 'F' ) ).ENDLOOP.
COMMIT ENTITIES.¡Con 100 libros: 100× accesos DB!
✅ Bueno (Batch)
" Un MODIFY para todosMODIFY 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 en lugar de SELECT *
❌ Malo (todos los campos)
SELECT * FROM I_Product INTO TABLE @DATA(lt_products).¡Carga 50 campos, pero solo usa 3!
✅ Bueno (solo campos necesarios)
SELECT Product, ProductName, Price FROM I_Product INTO TABLE @DATA(lt_products).Speedup: ~60% (menos tráfico de red)
6. Activar Table Buffering
Para datos maestros (rara vez cambia):
@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% (datos de memoria en lugar de DB)
PERO: ¡Solo para datos que cambian raramente!
7. FILTER en lugar de LOOP + IF
❌ Malo
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.✅ Bueno (FILTER Expression)
DATA(lt_active) = FILTER #( lt_customers WHERE status = 'ACTIVE' ).Speedup: ~30% (menos código, optimizado)
8. REDUCE en lugar de LOOP para agregaciones
❌ Malo
DATA lv_total TYPE p.
LOOP AT lt_orders INTO DATA(ls_order). lv_total = lv_total + ls_order-amount.ENDLOOP.✅ Bueno (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 con Associations
❌ Malo (cargar todo)
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}Problema: ¡Incluso cuando no se necesitan pedidos, siempre Join!
✅ Bueno (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 // Solo exponer, ¡sin Join!}Uso:
" Solo CustomerSELECT Customer, CustomerName FROM Z_Customer INTO TABLE @DATA(lt_customers).
" Con Orders (¡solo cuando sea necesario!)SELECT Customer, \_Orders-SalesOrder FROM Z_Customer INTO TABLE @DATA(lt_with_orders).Speedup: ~70% (cuando Orders raramente se necesita)
10. Usar SQL Trace
Encontrar cuellos de botella:
En ADT:
Run→Run Configurations- Tab
Trace Requests - Activar
SQL Trace - Ejecutar programa
Analizar:
❌ SELECT * FROM mara Duration: 2.5s Rows: 500,000
✅ SELECT matnr FROM mara WHERE mtart = 'FERT' Duration: 0.01s Rows: 1,000Acción: ¡Optimizar SELECTs lentos!
Checklist de rendimiento
Code Review
- Sin
SELECT * - WHERE-Clause usa índice
- Sin SELECT en LOOP
- EML agrupado
- FOR ALL ENTRIES verifica tabla vacía
- CDS Views para Joins
- FILTER/REDUCE en lugar de LOOP
- Buffering para datos maestros
Medición
- SQL Trace realizado
- Rendimiento < 1s para operaciones estándar
- Sin timeouts
- Consumo de memoria aceptable
Benchmarks de rendimiento
Ejemplo: 10.000 registros
| Operación | Antes | Después | Speedup |
|---|---|---|---|
| SELECT * | 2.5s | 0.3s (solo campos) | 88% |
| SELECT en 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% |
Total: De 26.3s a 2.0s = ¡92% Speedup!
Resumen
Ranking de Quick Wins:
- ⭐⭐⭐ SELECT en Loop → FOR ALL ENTRIES (+90%)
- ⭐⭐⭐ EML Batching (+85%)
- ⭐⭐⭐ Usar WHERE-Clause (+95%)
- ⭐⭐ CDS Views para Joins (+80%)
- ⭐⭐ Solo campos necesarios (+60%)
- ⭐⭐ Lazy Loading (+70%)
- ⭐ FILTER/REDUCE (+20-30%)
- ⭐ Buffering (+95% pero nicho)
- ⭐ SQL Trace (encuentra problemas)
- ⭐ Projection Views (+60%)
Mentalidad: ¡Usar poder de la DB, minimizar trabajo ABAP!
Ver también:
¡Happy Optimizing!