Langsamer ABAP-Report: wo die Laufzeit tatsächlich entsteht
Nicht die Datenbank ist das Problem, sondern die Zahl der Wege zu ihr. Wer die vier üblichen Muster kennt, holt in einem Nachmittag mehr heraus als mit jeder Hardwarediskussion.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Die Hoffnung war, dass die neue Datenbank den alten Code rettet
Der Ablauf ist bekannt. Ein System wird auf eine schnellere Datenbank gehoben, die Erwartung im Haus ist deutlich, und die Berichte, über die sich seit Jahren jemand beschwert, laufen danach ungefähr so lange wie vorher. Die Erklärung dafür steht in der Dokumentation zu Open SQL, und sie ist so unspektakulär wie belastbar: Jeder Datenbankzugriff belastet die Datenbank und die Verbindung zwischen Datenbank und Anwendungsserver. Wer einen Report schreibt, der zehntausendmal einzeln nachfragt, bezahlt zehntausendmal diesen Weg, und der wird durch schnelleres Antworten nur zu einem kleinen Teil billiger.
Das zweite Muster ist ebenso alt. Ein Programm liest großzügig, überträgt vollständige Zeilen mit allen Spalten an den Anwendungsserver und filtert anschließend im ABAP-Code das heraus, was tatsächlich gebraucht wird. Das ist bequem zu schreiben und in der Entwicklungsumgebung mit dreihundert Testsätzen völlig unauffällig. In der Produktion mit vier Millionen Sätzen wird daraus die Stelle, an der die Laufzeit entsteht, und sie ist im Quelltext nicht sichtbar, weil dort nur eine Zeile steht.
Der dritte Punkt ist der teuerste, weil er beim Umstieg systematisch auftritt. Auswertungen aus einem klassischen ERP waren häufig deshalb schnell, weil sie aus vorbereiteten Summen gelesen haben. In SAP S/4HANA ist das Universal Journal in der Tabelle ACDOCA der gemeinsame Belegspeicher für das Rechnungswesen, und die früheren Summensätze in Hauptbuch, Controlling, Material Ledger, Anlagenbuchhaltung sowie Kreditoren- und Debitorenbuchhaltung sind ebenso entfallen wie die Indextabellen, die bestimmte Selektionen beschleunigen sollten. Ein Report, der eins zu eins übernommen wurde, arbeitet danach auf einer ganz anderen Datenmenge.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Die Fälle, die im Alltag wirklich auflaufen
Sortiert nach dem, was du im Betrieb siehst, und nicht nach der Regel dahinter. Zu jedem Fall steht, warum die Zeit dort entsteht, und der Umbau, der ihn erledigt statt ihn zu verschieben.
Symptom
Der Report läuft in der Entwicklung in Sekunden und in der Produktion eine Viertelstunde, obwohl derselbe Code läuft.
Ursache
In der Schleife über eine Ergebnismenge steht ein weiterer Datenbankzugriff, der für jede Zeile einzeln ausgeführt wird. Bei dreihundert Testsätzen sind das dreihundert Zugriffe und damit unauffällig, bei vier Millionen Sätzen sind es vier Millionen. Jeder einzelne belastet die Datenbank und die Verbindung zum Anwendungsserver, und diese Verbindung wird durch eine schnellere Datenbank nicht überflüssig.
Lösung
Hol die benötigten Daten in einem Zugriff und lege sie in einer internen Tabelle ab, bevor die Schleife beginnt. Der übliche Weg ist eine Selektion über eine Menge von Schlüsseln oder eine Verknüpfung der beiden Tabellen in der Datenbank. Wichtig ist, dass die Ergebnismenge vorher eingeschränkt wird, sonst tauschst du viele kleine Zugriffe gegen einen sehr großen.
Symptom
Der Zugriff selbst sieht harmlos aus, der Lauf überträgt aber ein Vielfaches der Daten, die am Ende in der Liste stehen.
Ursache
Es werden alle Spalten gelesen, obwohl nur wenige gebraucht werden. Bei breiten Tabellen mit vielen Feldern ist der Unterschied erheblich, denn übertragen wird jede Spalte jeder Zeile. Die Regel lautet, die transportierte Datenmenge auf die benötigten Spalten zu beschränken, und sie wird beim Schreiben regelmäßig übergangen, weil eine Feldliste Tipparbeit ist.
Lösung
Gib die benötigten Felder ausdrücklich an, statt alles zu lesen. Das ist der Umbau mit dem besten Verhältnis von Aufwand zu Wirkung, weil er ohne fachliches Risiko auskommt und sich an vielen Stellen gleichzeitig anwenden lässt. Wenn dabei auffällt, dass niemand mehr weiß, welche Felder tatsächlich gebraucht werden, ist das bereits ein Ergebnis.
Symptom
Die Selektion holt eine große Menge, und im Programm wird anschließend der überwiegende Teil wieder verworfen.
Ursache
Die Einschränkung steht im ABAP-Code statt in der Bedingung des Datenbankzugriffs. Damit werden Zeilen gelesen, übertragen, im Speicher abgelegt und wieder weggeworfen. Die Regel dazu ist eindeutig: Die Menge der gelesenen Zeilen soll durch konkrete Bedingungen so klein wie möglich gehalten werden, und überflüssige Zeilen sollen gar nicht erst zur Anwendung transportiert werden.
Lösung
Verlagere jede Bedingung, die sich formulieren lässt, in den Datenbankzugriff. Für Bedingungen, die sich nicht direkt ausdrücken lassen, prüfe, ob eine Verknüpfung oder eine geeignete View das Problem löst. Was übrig bleibt, ist der Teil, der tatsächlich in die Anwendung gehört, und der ist erfahrungsgemäß klein.
Symptom
Die Datenbankzugriffe sind schnell, trotzdem verbringt der Lauf den Großteil der Zeit im eigenen Code.
Ursache
Zwei Schleifen über große interne Tabellen laufen ineinander, und der innere Zugriff sucht sequenziell. Die Laufzeit wächst dann nicht mit der Zahl der Sätze, sondern mit ihrem Produkt. Bei zwei Tabellen mit je zehntausend Einträgen sind das hundert Millionen Vergleiche, und das ist der Punkt, an dem ein Report ohne einen einzigen langsamen Datenbankzugriff eine Viertelstunde läuft.
Lösung
Gib der inneren Tabelle einen Zugriffsweg. Eine sortierte Tabelle oder eine Hash-Tabelle mit passendem Schlüssel bringt den Zugriff von linear auf beinahe konstant. Wenn die Tabellenart aus anderen Gründen nicht geändert werden kann, hilft ein Sekundärschlüssel. Beides ist eine Änderung an der Deklaration und nicht an der Logik, also überschaubar im Risiko.
Symptom
Die Selektion ist sinnvoll eingeschränkt und dauert trotzdem lange, obwohl nur wenige Zeilen zurückkommen.
Ursache
Die Bedingung passt nicht zu den vorhandenen Zugriffswegen der Tabelle. Sekundäre Indizes verbessern die Selektionsleistung, wenn sie zur Bedingung passen, und sie helfen nicht, wenn die Felder in der Bedingung andere sind. Dazu kommt der Fall, dass eine kleine, selten geänderte und häufig gelesene Tabelle nicht gepuffert ist, obwohl sie sich dafür anbieten würde.
Lösung
Prüfe zuerst, ob die Bedingung sich auf vorhandene Zugriffswege stützen kann, und ändere im Zweifel die Bedingung statt die Tabelle. Ein zusätzlicher Index ist ein Eingriff mit dauerhaften Kosten bei jeder Änderung an der Tabelle und gehört deshalb begründet. Bei kleinen, häufig gelesenen und selten geänderten Tabellen ist die Pufferung der wirksamere Hebel.
Symptom
Ein Bericht aus dem Rechnungswesen war im Altsystem schnell und ist nach dem Umstieg deutlich langsamer geworden.
Ursache
Er hat vorher aus vorbereiteten Summen gelesen. In SAP S/4HANA ist das Universal Journal in der Tabelle ACDOCA der gemeinsame Belegspeicher, interne und externe Sicht lesen aus derselben Quelle, und die früheren Summensätze in Hauptbuch, Controlling, Material Ledger, Anlagenbuchhaltung sowie Kreditoren- und Debitorenbuchhaltung sind ebenso entfallen wie die Indextabellen. Derselbe Bericht arbeitet damit auf einer völlig anderen Datenmenge.
Lösung
Das ist kein Fall für eine Programmoptimierung, sondern für eine Entscheidung über die Datenquelle. Prüfe zuerst, ob eine vorhandene Auswertung dieselbe Frage bereits beantwortet. Wenn eigener Code bleiben soll, gehört die Verdichtung dorthin, wo die Daten liegen, statt einzelne Belege in die Anwendung zu holen und dort zu summieren.
Fünf Fragen, und du weißt, wo die Zeit bleibt
- 01 Wie viele Datenbankzugriffe macht der Lauf, und wie viele davon stehen in einer Schleife?
- 02 Wie viele Zeilen kommen zurück, und wie viele davon werden anschließend verworfen?
- 03 Werden alle Spalten geholt, obwohl nur wenige gebraucht werden?
- 04 Laufen zwei Schleifen über große interne Tabellen ineinander, ohne passenden Zugriffsweg?
- 05 Liest der Report noch die Quelle, für die er ursprünglich geschrieben wurde?
Danach findest du die Stelle, statt am Code entlangzuraten
Laufzeit entsteht an wenigen, immer wiederkehrenden Stellen. Wer diese sechs Punkte anwendet, braucht für einen typischen langsamen Report einen halben Tag, und ein erheblicher Teil dieser Zeit geht in die Messung und nicht in den Umbau.
Erst messen, dann umbauen
Ohne eine Messung baust du die Stelle um, die dir am ehesten auffällt, und das ist selten die teure. Die Frage lautet, wie viele Datenbankzugriffe stattfinden und wie viele Zeilen dabei übertragen werden, nicht, welche Zeile im Quelltext am kompliziertesten aussieht.
Die Zahl der Zugriffe reduzieren, nicht ihre Dauer
Ein Zugriff, der tausendmal stattfindet, ist teurer als einer, der einmal etwas länger dauert. Der wirksamste Umbau ist deshalb fast immer der, der aus vielen kleinen Zugriffen einen großen macht und das Ergebnis in eine interne Tabelle holt.
Die Trefferzahl klein halten
Die Menge der gelesenen Zeilen sollte so klein wie möglich sein, eingeschränkt über konkrete Bedingungen. Überflüssige Zeilen sollten gar nicht erst zur Anwendung übertragen und dort ausgewertet werden, denn dort kosten sie Übertragung, Speicher und Laufzeit gleichzeitig.
Die Datenmenge klein halten
Übertragen wird nur, was gebraucht wird, also eine ausdrückliche Feldliste statt aller Spalten. Bei breiten Tabellen ist das oft der einfachste wirksame Eingriff überhaupt, und er ist ohne fachliches Risiko umsetzbar.
Interne Tabellen als eigene Kostenstelle behandeln
Auch nach dem Lesen entsteht Laufzeit. Zwei ineinander laufende Schleifen über große interne Tabellen ohne passenden Zugriffsweg kosten mehr als der Datenbankzugriff davor. Sortierte Tabellen, Hash-Tabellen und Sekundärschlüssel sind die Antwort darauf.
Beim Umstieg die Datenquelle prüfen
Ein Report, der im Altsystem aus Summen gelesen hat, liest nach dem Umstieg aus dem Belegbestand. Das ist keine Frage der Programmierung, sondern der Datenquelle, und sie muss zuerst geklärt werden, bevor jemand am Code optimiert.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Wo die Zeit tatsächlich hingeht
Die Dokumentation zu Open SQL formuliert es unmissverständlich: Die Leistung eines Programms wird häufig von der Effizienz seiner Datenbankzugriffe bestimmt. In einer Umgebung mit getrenntem Datenbank- und Anwendungsserver belastet jeder einzelne Zugriff sowohl die Datenbank als auch die Verbindung zwischen beiden, und diese Last soll so gering wie möglich gehalten werden. Das ist der Satz, an dem sich die Hoffnung bricht, eine schnellere Datenbank rette den vorhandenen Code.
Daraus folgen zwei Regeln, und fast alles andere ist eine Anwendung davon. Erstens: die Trefferzahl klein halten, also die Menge der ausgewählten Zeilen durch konkrete Bedingungen auf das beschränken, was wirklich gebraucht wird. Überflüssige Zeilen sollen gar nicht erst zum Anwendungsserver transportiert und dort ausgewertet werden. Zweitens: die Datenmenge klein halten, also nur die benötigten Spalten übertragen statt vollständiger Zeilen.
Dazu kommen zwei Hebel, die weniger bekannt sind. Eine Datenbanktabelle, die häufig gelesen und selten geändert wird, sollte gepuffert werden, und die Zeitersparnis dabei ist erheblich. Und sekundäre Indizes verbessern die Selektionsleistung, sofern sie vorhanden sind und zu der gestellten Bedingung passen. Beide Punkte werden in der Praxis eher zu selten als zu oft genutzt, weil sie beim Schreiben eines Programms nicht sichtbar sind.
Warum die Schleife mit Einzelzugriff das teuerste Muster ist
Es gibt in ABAP kein Muster, das so oft für lange Laufzeiten sorgt wie ein Datenbankzugriff innerhalb einer Schleife. Der Grund liegt nicht darin, dass der einzelne Zugriff langsam wäre, sondern in seiner Häufigkeit. Jeder Zugriff ist ein Weg zur Datenbank und zurück, mit allem, was dazugehört, und dieser Weg fällt bei jeder einzelnen Zeile erneut an. Bei wenigen hundert Durchläufen fällt das nicht auf, bei einigen hunderttausend bestimmt es die gesamte Laufzeit.
Der Umbau ist immer derselbe: Aus vielen kleinen Zugriffen wird einer, dessen Ergebnis in einer internen Tabelle landet, und die Schleife arbeitet danach auf dieser Tabelle statt auf der Datenbank. Der zweite Weg ist die Verknüpfung, bei der die Datenbank die Zusammenführung übernimmt und nur das Ergebnis überträgt. Welcher der beiden passt, hängt davon ab, wie viele Zeilen dabei entstehen und ob die Verknüpfung Zeilen vervielfacht.
Ein Hinweis zur Vorsicht, weil dieser Umbau gern über das Ziel hinausschießt: Wenn du aus tausend Einzelzugriffen einen machst, der zwei Millionen Zeilen liefert, hast du das Problem verschoben und nicht gelöst. Die Trefferzahl bleibt die erste Regel. Der richtige Umbau reduziert die Zahl der Zugriffe und die Zahl der Zeilen gleichzeitig, und dafür muss die Einschränkung vorher stehen und nicht hinterher im Code.
Interne Tabellen sind der zweite Ort, an dem Laufzeit entsteht
Wenn die Datenbankzugriffe in Ordnung sind und der Lauf trotzdem dauert, liegt die Zeit fast immer in der Verarbeitung interner Tabellen. Der klassische Fall sind zwei ineinander laufende Schleifen: Für jede Zeile der äußeren Tabelle wird die innere durchsucht. Ist die innere Tabelle eine Standardtabelle und wird sequenziell durchsucht, wächst der Aufwand mit dem Produkt beider Größen, und das ist die Stelle, an der aus Sekunden Minuten werden.
Die ABAP-Dokumentation behandelt dazu mehrere Stellschrauben, und drei davon lösen die meisten Fälle. Die Wahl der Tabellenart entscheidet über den Zugriffsweg: Eine sortierte Tabelle erlaubt eine binäre Suche über den Schlüssel, eine Hash-Tabelle einen Zugriff über den Schlüssel unabhängig von der Größe. Sekundärschlüssel erlauben denselben Vorteil, wenn die Tabellenart aus anderen Gründen nicht geändert werden kann. Und die selektive Datenübertragung sorgt dafür, dass beim Kopieren zwischen Tabellen nur die tatsächlich benötigten Felder bewegt werden.
Ebenso lohnt der Blick auf das Löschen von Zeilen und auf das Sortieren. Zeilen einzeln aus der Mitte einer großen Tabelle zu entfernen, ist teuer, weil die Verwaltung nachziehen muss, und in vielen Fällen ist es günstiger, die verbleibenden Zeilen in eine neue Tabelle zu übernehmen. Sortieren ist ebenfalls kein kostenloser Vorgang, und ein Sortiervorgang innerhalb einer Schleife ist ein sicheres Zeichen dafür, dass etwas anders aufgebaut gehört.
Was der Umstieg an der Datenlage verändert hat
Ein Teil der Berichte, die nach einem Umstieg langsam wirken, ist nicht schlechter programmiert als vorher. Sie arbeiten auf einer anderen Datenlage. In SAP S/4HANA ist das Universal Journal in der Tabelle ACDOCA der gemeinsame Belegspeicher für das Rechnungswesen. Interne und externe Sicht lesen aus derselben Quelle, verbindendes Element ist das Konto, und die früheren Summensätze sowie die Indextabellen sind entfallen.
Für Programme, die auf diese Summen oder Indextabellen zugegriffen haben, gibt es damit keinen kleinen Umbau. Entweder es existiert eine vorhandene Auswertung, die dieselbe Frage bereits beantwortet, dann ist das der günstigste Weg. Oder der eigene Code bleibt, dann gehört die Verdichtung dorthin, wo die Daten liegen, statt Belegzeilen zum Anwendungsserver zu holen und dort zu summieren. Der Unterschied zwischen diesen beiden Wegen ist bei Millionen von Zeilen kein gradueller.
Deshalb gehört diese Prüfung an den Anfang und nicht ans Ende. Wer zuerst an einem Report optimiert, dessen Datenquelle gar nicht mehr existiert oder ganz anders aussieht, verbringt einen Tag mit Feinarbeit an der falschen Stelle. Die erste Frage bei jedem langsamen Bericht nach einem Umstieg lautet deshalb nicht, wo die Schleife steht, sondern woher die Zahlen kommen.
Messen statt raten, und zwar in dieser Reihenfolge
Die Reihenfolge ist wichtiger als das Werkzeug. Zuerst willst du wissen, ob die Zeit in der Datenbank oder im eigenen Code liegt. Diese eine Angabe entscheidet, welche Hälfte dieser Seite für dich zutrifft, und sie erspart es, an der falschen Stelle zu suchen. Liegt die Zeit in der Datenbank, ist die nächste Frage die nach der Zahl der Zugriffe und der Zahl der übertragenen Zeilen. Liegt sie im eigenen Code, geht es um Schleifen und Tabellenarten.
Danach gilt eine schlichte Regel: eine Änderung, eine Messung. Wer drei Umbauten gleichzeitig macht, weiß hinterher nicht, welcher gewirkt hat, und übernimmt zwei davon ohne Grund in den nächsten Report. Das ist kein akademischer Punkt, denn manche vermeintlichen Verbesserungen kosten an anderer Stelle mehr, als sie einbringen, etwa ein zusätzlicher Index, der bei jeder Änderung an der Tabelle mitgepflegt werden muss.
Und miss mit einer Datenmenge, die der Produktion nahekommt. Eine Optimierung, die auf dreihundert Testsätzen geprüft wurde, ist keine Optimierung, sondern eine Vermutung. Die meisten Muster auf dieser Seite verhalten sich bei kleinen Mengen unauffällig, und genau deshalb entstehen sie überhaupt: Sie sehen im Test völlig in Ordnung aus.
Dazu passende Kurse
Weil sich diese Muster an fremden Beispielen schlecht üben lassen, sind ABAP-Kurse zu Reports und Datenmodell der direktere Weg zu Code, der auch in der Produktion trägt.
Und weil ein Bericht nur so gut ist wie das Verständnis der Tabellen darunter, gehören SAP-Kurse zum Datenmodell hinter den Auswertungen in dieselbe Vorbereitung.
Wie sicher bist du beim Thema wirklich?
Lesen fühlt sich schnell nach Können an. Ein kurzer Test zeigt dir, was davon schon sitzt und wo sich ein Kurs lohnt. Kostenlos, ohne Anmeldung, mit einer Erklärung zu jeder Antwort.
Wo du genau das übst
Häufige Fragen
Warum bringt eine schnellere Datenbank nichts, wenn der Code gleich bleibt?
Ist ein Zugriff über eine Verknüpfung immer besser als mehrere einzelne?
Lohnt sich ein zusätzlicher Index auf einer großen Tabelle?
Unsere Zugriffe sind sauber, der Report dauert trotzdem. Woran liegt das?
Warum ist derselbe Bericht nach dem Umstieg langsamer geworden?
Sollen wir solche Berichte lieber neu bauen oder umbauen?
Passt thematisch dazu
Wenn die Zugriffe sauber aussehen und der Lauf trotzdem dauert, bleibt als nächster Schritt, einen Ausführungsplan von innen nach außen zu lesen .
Deine Ansprechpartner
Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.
Yves Hoppe
Weiterbildung & Beratung
Hilft dir, aus dem SAP-Programm den passenden Kurs für deinen Stand zu finden.
Norbert Jansen
Beratung & Inhouse
Plant mit dir Inhouse-Trainings, die auf eure Abläufe und euren Datenbestand zugeschnitten sind.
Die Stelle finden, an der die Laufzeit entsteht
Wie ein Report aussieht, der auch bei Millionen Sätzen trägt, und wie du die teure Stelle in fremdem Code findest, arbeitest du bei cmt an eigenen Programmen durch.