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.