La optimización del rendimiento es crucial para programas ABAP fáciles de usar y que ahorran recursos. Este artículo muestra las técnicas más importantes para mejorar el rendimiento.
Herramientas de Análisis de Rendimiento
Herramienta Transacción Descripción SQL Trace ST05 Analizar accesos a base de datos ABAP Trace SAT Análisis en tiempo de ejecución Code Inspector SCI Análisis estático de código ABAP Profiler SAT Perfilado detallado Explain Plan ST05 Plan de ejecución SQL
Optimización de SQL
Leer Solo las Columnas Necesarias
" Malo - leer todas las columnas
SELECT * FROM mara INTO TABLE @ DATA (lt_mara)
" Bueno - solo columnas necesarias
SELECT matnr, maktx, mtart, matkl
INTO TABLE @ DATA (lt_mara_opt)
SELECT con Uso de Índice
" Malo - no se puede usar índice
SELECT * FROM vbap INTO TABLE @ DATA (lt_vbap)
" Bueno - usar índice primario
SELECT * FROM vbap INTO TABLE @ DATA (lt_vbap)
" Bueno - usar índice secundario (si existe)
SELECT * FROM vbap INTO TABLE @ DATA (lt_vbap)
%_HINTS ORACLE 'INDEX(VBAP VBAP~Z01)' .
Uso Correcto de FOR ALL ENTRIES
" ¡La verificación de tabla vacía es OBLIGATORIA!
IF lt_orders IS NOT INITIAL .
SELECT vbeln, posnr, matnr, kwmeng
FOR ALL ENTRIES IN @lt_orders
WHERE vbeln = @lt_orders-vbeln
INTO TABLE @ DATA (lt_items).
" Alternativa: JOIN en lugar de FOR ALL ENTRIES
SELECT v~vbeln, v~posnr, v~matnr, v~kwmeng
INNER JOIN @lt_orders AS o ON v~vbeln = o~vbeln
INTO TABLE @ DATA (lt_items_join).
Usar Funciones de Agregación
" Malo - leer todos los datos y sumar
SELECT * FROM vbap INTO TABLE @ DATA (lt_all)
DATA (lv_sum) = REDUCE kwmeng( INIT sum = 0
NEXT sum = sum + wa-kwmeng ).
" Bueno - la base de datos suma
SELECT SUM ( kwmeng ) AS total
Activar Buffering
" Activar buffering de tablas en SE11:
" - Buffering completo (tablas pequeñas)
" - Buffering genérico (parte de campos clave)
" - Buffering de registro individual
" Omitir buffer cuando sea necesario
SELECT SINGLE * FROM t001 BYPASSING BUFFER
Operaciones en Masa
" Malo - INSERTs individuales
LOOP AT lt_new_data INTO DATA (ls_data).
INSERT ztable FROM ls_data.
INSERT ztable FROM TABLE lt_new_data.
UPDATE ztable FROM TABLE lt_update_data.
DELETE ztable FROM TABLE lt_delete_data.
Tablas Internas
Elegir el Tipo de Tabla Correcto
" STANDARD TABLE - acceso secuencial, APPEND
DATA : lt_standard TYPE STANDARD TABLE OF sflight.
" SORTED TABLE - búsqueda binaria, acceso ordenado
DATA : lt_sorted TYPE SORTED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
" HASHED TABLE - acceso directo por clave
DATA : lt_hashed TYPE HASHED TABLE OF sflight
WITH UNIQUE KEY carrid connid fldate.
Optimizar READ TABLE
READ TABLE lt_standard INTO DATA (ls_line)
" Bueno - búsqueda binaria (¡la tabla debe estar ordenada!)
SORT lt_standard BY carrid.
READ TABLE lt_standard INTO ls_line
WITH KEY carrid = 'LH' BINARY SEARCH .
" Bueno - SORTED o HASHED TABLE
READ TABLE lt_sorted INTO ls_line
WITH TABLE KEY carrid = 'LH' connid = '0400' fldate = '20250115' .
Usar Claves Secundarias
" Definir clave secundaria
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.
" Acceso mediante clave secundaria
READ TABLE lt_flights INTO DATA (ls_flight)
WITH KEY by_plane COMPONENTS planetype = 'A380' .
LOOP AT lt_flights INTO ls_flight USING KEY by_plane
WHERE planetype = 'A380' .
Optimización de LOOP
" Malo - WHERE sin índice
LOOP AT lt_large_table INTO DATA (ls_line)
" Bueno - WHERE en tabla ordenada
LOOP AT lt_sorted INTO ls_line
WHERE carrid = 'LH' . " Usa la ordenación
" Bueno - ASSIGNING en lugar de INTO (sin copia)
LOOP AT lt_table ASSIGNING FIELD-SYMBOL (<ls_line>).
<ls_line>-status = 'P' . " Modificación directa
" Bueno - REFERENCE INTO para operaciones de lectura
LOOP AT lt_table REFERENCE INTO DATA (lr_line).
DATA (lv_value) = lr_line->field.
Joins de Tablas en Memoria
LOOP AT lt_orders INTO DATA (ls_order).
LOOP AT lt_items INTO DATA (ls_item)
WHERE order_id = ls_order-order_id.
" Bueno - SORTED TABLE con 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.
Paralelización
Llamadas RFC Paralelas
DATA : lv_task TYPE string ,
lt_results TYPE TABLE OF ty_result.
" Iniciar tareas paralelas
LOOP AT lt_work_packages INTO DATA (ls_package).
lv_counter = lv_counter + 1 .
lv_task = | TASK { lv_counter }| .
CALL FUNCTION 'Z_PROCESS_PACKAGE'
STARTING NEW TASK lv_task
DESTINATION IN GROUP DEFAULT
CALLING on_task_complete ON END OF TASK
communication_failure = 2 .
" Fallback: procesar síncronamente
CALL FUNCTION 'Z_PROCESS_PACKAGE'
es_result = DATA (ls_result).
APPEND ls_result TO lt_results.
" Esperar a todas las tareas
WAIT UNTIL lv_completed = lv_counter UP TO 300 SECONDS .
FORM on_task_complete USING p_task TYPE clike .
DATA : ls_result TYPE ty_result.
RECEIVE RESULTS FROM FUNCTION 'Z_PROCESS_PACKAGE'
APPEND ls_result TO lt_results.
lv_completed = lv_completed + 1 .
Framework SPTA
" SPTA para procesamiento paralelo
DATA : lt_input TYPE spta_t_input,
lt_output TYPE spta_t_output.
LOOP AT lt_work_items INTO DATA (ls_item).
APPEND INITIAL LINE TO lt_input ASSIGNING FIELD-SYMBOL (<ls_input>).
<ls_input>-data = ls_item.
CALL FUNCTION 'SPTA_PARA_PROCESS_START_2'
server_group = 'parallel_generators'
before_rfc_callback = 'PREPARE_PACKAGE'
in_rfc_callback = 'PROCESS_PACKAGE'
after_rfc_callback = 'COLLECT_RESULT'
Operaciones de String
Concatenación Eficiente
" Malo - CONCATENATE repetido
DATA : lv_result TYPE string .
LOOP AT lt_parts INTO DATA (lv_part).
CONCATENATE lv_result lv_part INTO lv_result.
" Bueno - String Templates
lv_result = REDUCE string( INIT r = ``
" Bueno - CONCATENATE LINES OF
CONCATENATE LINES OF lt_parts INTO lv_result SEPARATED BY space .
Cachear Expresiones Regulares
" Malo - compilar regex en cada llamada
LOOP AT lt_strings INTO DATA (lv_string).
FIND REGEX '\d{4}-\d{2}-\d{2}' IN lv_string.
" Bueno - compilar regex una vez
DATA (lo_regex) = NEW cl_abap_regex( pattern = '\d{4}-\d{2}-\d{2}' ).
DATA (lo_matcher) = lo_regex->create_matcher( text = `` ).
LOOP AT lt_strings INTO lv_string.
lo_matcher->match( text = lv_string ).
Optimización de Memoria
Liberar Tablas Grandes
" Liberar memoria explícitamente
DATA (lv_sum) = REDUCE i( INIT s = 0
FOR <line> IN lt_large_table
NEXT s = s + <line>-amount ).
FREE lt_large_table. " Liberar inmediatamente
Procesamiento por Paquetes
DATA : lv_offset TYPE i VALUE 0 ,
lv_limit TYPE i VALUE 1000 .
SELECT * FROM large_table
INTO TABLE @ DATA (lt_package)
IF lt_package IS INITIAL .
LOOP AT lt_package INTO DATA (ls_line).
lv_offset = lv_offset + lv_limit.
Buffering
Shared Memory Objects
" Shared Memory para datos leídos frecuentemente
CLASS zcl_cache DEFINITION .
RETURNING VALUE (rt_config) TYPE ty_config_tab.
CLASS zcl_cache IMPLEMENTATION .
" Verificar Shared Buffer
IMPORT config = rt_config FROM SHARED BUFFER indx(zc)
SELECT * FROM zconfig INTO TABLE rt_config.
" Guardar en Shared Buffer
EXPORT config = rt_config TO SHARED BUFFER indx(zc)
ABAP Shared Objects
" Shared Objects para datos complejos
" Obtener handle del área
DATA (lo_handle) = zcl_my_area=>attach_for_read( ).
DATA (lo_root) = lo_handle->get_root( ).
DATA (lt_data) = lo_root->get_cached_data( ).
Análisis de Rendimiento
Evaluar SQL Trace
" - Identical Selects (misma consulta varias veces)
" - SELECT * (demasiadas columnas)
" - Demasiados registros individuales
Runtime Analysis (SAT)
SET RUN TIME ANALYZER ON .
" ... ejecutar código ...
SET RUN TIME ANALYZER OFF.
" O mediante transacción SAT
Checks de Code Inspector
" SCI - variantes de check importantes:
" - APPEND en LOOP en lugar de Array
" - Condición WHERE faltante
" - INTO CORRESPONDING FIELDS
" - Operaciones de tabla ineficientes
Medición y Benchmarking
GET RUN TIME FIELD lv_start.
LOOP AT lt_table INTO DATA (ls_line).
GET RUN TIME FIELD lv_end.
lv_diff = lv_end - lv_start.
WRITE : / 'Tiempo de ejecución:' , lv_diff, 'microsegundos' .
DATA (lv_ts_start) = utclong_current( ).
DATA (lv_ts_end) = utclong_current( ).
DATA (lv_seconds) = cl_abap_tstmp=>subtract(
Mejores Prácticas
Medir antes de optimizar : Siempre perfilar primero, luego optimizar
Reducir carga de base de datos : Menos SELECTs, WHERE eficiente
Tipo de tabla correcto : HASHED para acceso por clave, SORTED para rangos
Liberar memoria : FREE para tablas grandes después del uso
Paralelización : Para tareas independientes
Buffering : Para datos leídos frecuentemente y raramente modificados
Transacciones Importantes
Transacción Descripción ST05 SQL/Buffer Trace SAT ABAP Trace SCI Code Inspector ST12 Trace combinado SM50 Work Processes ST02 Estadísticas de buffer
Temas Relacionados