No hagas esto nunca dentro de un LOOP

Una de las malas prácticas más conocidas en ABAP —y también una de las más comunes cuando empiezas— es hacer consultas a base de datos dentro de un LOOP.

Al principio parece algo lógico e incluso cómodo. Necesitas un dato → haces un SELECT SINGLE → continúas el proceso. El problema es que esta práctica puede afecta al rendimiento de un programa, sobre todo cuando trabaja con grandes volúmenes de datos.

Ejemplo:

LOOP AT lt_vbak INTO DATA(ls_vbak).

SELECT SINGLE name1
FROM kna1
INTO @DATA(lv_name1)
WHERE kunnr = @ls_vbak-kunnr.

ENDLOOP.

A simple vista parece correcto. Pero piensa qué ocurre realmente:

  • Si el LOOP tiene 10 registros → haces 10 SELECT
  • Si tiene 1.000 registros → haces 1.000 SELECT
  • Si tiene 100.000 registros → haces 100.000 SELECT

Estás lanzando una consulta a base de datos en cada iteración. Y acceder a base de datos es una de las operaciones más costosas en SAP.

¿Por qué es una mala práctica?

  • Multiplica los accesos a base de datos. Cada iteración lanza una consulta nueva, y cuantos más registros tenga el LOOP, más accesos haces.
  • Escala muy mal. Con pocos registros quizá no se nota el problema, pero en producción, con grandes volúmenes de datos, el rendimiento puede degradarse muchísimo.
  • Mayor carga del sistema. No solo afecta a tu programa, también aumenta carga en la base de datos, en la red y afecta a otros procesos.
  • Programas más lentos. El tiempo de ejecución puede multiplicarse innecesariamente.

La alternativa correcta

La buena práctica es:

Paso 1: obtener todos los datos necesarios en un único SELECT

Opción 1: JOIN (cuando los datos están en tablas relacionadas)

SELECT vbak~kunnr, kna1~name1
  FROM kna1 AS kna1
  INNER JOIN lt_vbak AS vbak
  ON vbak~kunnr = kna1~kunnr
  INTO TABLE @DATA(lt_kna1).

En sistemas modernos (especialmente S/4HANA), normalmente se prioriza JOIN frente a otras alternativas.

Opción 2: FOR ALL ENTRIES

Útil cuando tu sistema es muy antiguo y no te permite hacer JOIN de tablas internas.

IF lt_vbak IS NOT INITIAL.
  SELECT kunnr,
         name1
    FROM kna1
    INTO TABLE @DATA(lt_kna1)
    FOR ALL ENTRIES IN @lt_vbak
    WHERE kunnr = @lt_vbak-kunnr.
ENDIF.

⚠️ Importante: Siempre verifica que la tabla origen no esté vacía antes del FOR ALL ENTRIES. Si no lo haces, SAP puede devolver TODOS los registros de la tabla.

Paso 2: leer los datos desde memoria dentro del LOOP

LOOP AT lt_vbak INTO DATA(ls_vbak).

  READ TABLE lt_kna1 INTO DATA(ls_kna1) WITH KEY kunnr = ls_vbak-kunnr.
   ....

ENDLOOP.

Leer desde memoria es muchísimo más rápido que acceder continuamente a base de datos. Incluso mejor: tablas HASHED o SORTED.

Si vas a hacer muchas lecturas dentro del LOOP, puedes mejorar todavía más el rendimiento usando:

  • HASHED TABLE
  • SORTED TABLE

Porque el acceso por clave será mucho más rápido que un READ TABLE secuencial. Esto es especialmente importante en programas con grandes volúmenes de datos.

Por eso en ABAP Evita SELECT dentro de LOOP, y mejor lee datos masivamente y procesarlos en memoria.