Diesen Artikel habe ich ursprünglich im SAP Community Network veröffentlicht.

Wie Sie sicherlich alle wissen, gibt es zahlreiche Möglichkeiten, eine interne Tabelle zu durchlaufen. Die wahrscheinlich beliebtesten sind LOOP AT table INTO line, LOOP AT table ASSIGNING <fs> und LOOP AT table REFERENCE INTO dref. Jeder sollte sich der Leistungsprobleme und Nebenwirkungen bewusst sein, die bei der Verwendung der verschiedenen Versionen auftreten können – am wichtig ist, dass LOOP AT … INTO … eine Kopie jeder einzelnen Tabellenzeile erstellt, während die anderen Varianten nur Zeiger oder Adressen verschieben. Einerseits bedeutet dies, dass bei „breiten“ Tabellen viel Zeit für das Verschieben von Daten aufgewendet wird, andererseits bedeutet dies aber auch, dass Sie die Daten nach der Änderung wieder in die Tabelle kopieren müssen, während die anderen Varianten eine direkte Bearbeitung der Tabelleninhalte ermöglichen.

Ich bin ein neugieriger Mensch. Ich wollte wissen, wie viel langsamer es wäre, den Inhalt der Tabelle zu kopieren, anstatt ihn direkt zu bearbeiten, also habe ich ein kleines Programm zusammengebastelt, das eine Reihe von Iterationen an Tabellen verschiedener Größen durchführt und die für die verschiedenen Varianten benötigte Zeit vergleicht. Nun bin ich kein Künstler, aber meine grafischen Fähigkeiten reichen aus, um einfache Diagramme zu erstellen:

Diese Grafik zeigt, wie viel Zeit benötigt wird, um Tabellen mit unterschiedlicher Breite bis zu ca. 32.000 Zeichen zu durchlaufen (jeweils 10.000 Zeilen, nur die Größe der Zeilenlänge ändert sich!). Ich habe den Diagrammen gleitende Durchschnittslinien hinzugefügt, da die Datenpunkte aus verschiedenen Gründen (wahrscheinlich Ausrichtung, Seitengrößen und andere Auswirkungen der Speicherverwaltung) ziemlich stark schwanken. Wie Sie sehen können, sind die Varianten ASSIGNING (grün) und REFERENCE INTO (blau) nahezu identisch, was den Zeitaufwand betrifft, während die Variante INTO (rot) viel teurer sein kann.

Und noch einmal, nur aus Neugier, hier eine Detailaufnahme der Tabellengrößen zwischen 1 und 1000 Zeichen:

Ich bin mir sehr wohl bewusst, dass diese Diagramme eher subjektiv sind und je nach Maschinentyp, Unicode-/Nicht-Unicode-Systemen und anderen Faktoren variieren können. Im Zweifelsfall messen – aber denken Sie daran, dass es normalerweise nicht notwendig ist, Tonnen von Daten zu durchsuchen, nur um ein paar Zahlen zusammenzuzählen. Und wenn wir schon dabei sind, gibt es auch die TRANSPORTING NO FIELDS-Variante, die sich als recht nützlich erweisen kann, um Zeilen zu zählen oder das Vorhandensein von Werten zu überprüfen.

Nach dieser etwas längeren Einführung kommen wir nun zur heutigen ABAP-Falltür. Eigentlich handelt es sich eher um eine übergroße Mausefalle – gefährlich genug, um sich den Fuß zu verletzen, aber nicht groß genug, um einen ganzen ABAP-Entwickler zu verschlucken. Sehen Sie sich das folgende Programm an:

DATA: numbers TYPE TABLE OF i,
      sum TYPE i.
FIELD-SYMBOLS: <number> TYPE i.

DO 100 TIMES.
  APPEND sy-index TO numbers.
ENDDO.

sum = 0.
LOOP AT numbers ASSIGNING <number>.
  sum = sum + <number>.
ENDLOOP.
WRITE: / 'Sum 1:', sum.

CLEAR sum.
LOOP AT numbers INTO <number>.
  ADD <number> TO sum.
ENDLOOP.
WRITE: / 'Sum 2:', sum.</pre>

Auf den ersten Blick sind dies nur zwei Varianten, wie man die in einer Tabelle enthaltenen Werte zusammenfassen kann – die erste ist etwas mehr C-Zeilen-orientiert, die zweite ist für COBOL-Liebhaber. Aber werfen wir einen Blick auf die Ausgabe:

Sum 1: 5.050

Sum 2: 5.049

Was zum…? Okay, Sie haben das Problem wahrscheinlich schon erkannt. Nachdem der erste LOOP-Schleifendurchlauf abgeschlossen ist, bleibt das Feldsymbol der letzten Zeile der Tabelle zugewiesen, und durch die Verwendung des Feldsymbols als Ziel des zweiten LOOP-Schleifendurchlaufs wird die letzte Zeile der Tabelle bei jeder Iteration geändert. Dies führt zu einer falschen Summe sowie zu einem unfreiwillig geänderten Tabelleninhalt. Dasselbe würde bei einer REFERENCE INTO-Schleife passieren, aber das ist weniger wahrscheinlich, da die Syntax anders ist.

Die beste Möglichkeit, dies zu verhindern, besteht darin, das verwendete Feldsymbol direkt nach der ENDLOOP-Anweisung mit UNASSIGN zu entfernen. Auf diese Weise stürzt das Programm zumindest kontrolliert ab, anstatt stillschweigend falsche Ergebnisse zu produzieren.