Mit der Einführung von SAP BW on HANA im Jahre 2010 wurden viele bisherigen Maßnahmen zur Performancesteigerung in BW-Systemen obsolet; gleichzeitig drängen sich aber viele neuen Fragen bezüglich der neuartigen Plattform auf. Von großer Relevanz ist dabei auch die Frage, ob es immer noch sinnvoll ist, die sogenannten "Advanced Business Application Programming-Routinen" zu cachen. Denn mit HANA werden die Daten einerseits in der unter einem Applikationsserver liegenden Datenbank im Hauptspeicher abgelegt und andererseits für Abfragen optimiert. Hinzu kommt, dass die Abfragen in Routinen systembedingt auf dem Applikationsserver ausgeführt werden. Die Frage nach der Sinnhaftigkeit der Nutzung eines Caches für ABAP-Routine-Abfragen soll deshalb im nachfolgenden Blogbeitrag eingehend erläutert werden:
Bei häufig wiederkehrenden Daten lässt sich dies grundsätzlich bejahen. Denn wenn beispielsweise das Attribut "Kontinent" von dem Info-Objekt "Land" hinzugelesen werden soll, ist der zeitliche Overhead eines Zugriffs durch den SQL Parser, das Netzwerk, etc. auf HANA wiederkehrend für jede Zeile zu hoch. Zwischen dem ABAP-Programm und den eigentlichen Daten liegen etliche technische Layer, welche damit wiederholend ausgeführt werden. Ist es jedoch notwendig, mehrere Joins zwischen Tabellen durchzuführen oder ist die Anzahl der zu lesenden Zeilen sehr groß, kippt der Vorteil wieder in Richtung der HANA-Datenbank.
Nach meinen Erfahrungen bei Kunden mit großen Datenmengen beschleunigt ein Cache im ABAP die DTP-Ausführung in einem SAP BW on HANA System teils um den Faktor 3. Dies ist natürlich immer abhängig von der Situation (z.B. Datenverteilung, Homogenität der Daten etc.), sowie von der aufgebauten Infrastruktur. Alles noch ohne Einsatz des Shared Memory. Dieser führt für alle Datenpakete zusammen, also pro Beladung, nur eine Abfrage auf die Datenbank aus. Im Handling ist dieser aber unnötig kompliziert.
Häufig eingesetzten Cache-Implementierungen im ABAP
Full Table
In einer internen Tabelle wird die gesamte bzw. der notwendige Teil einer Datenbanktabelle geladen und steht während der DTP Ausführung zur Verfügung. Ein Zugriff auf die Datenbank pro Lookup erfolgt nicht mehr. Dabei sollte jedoch beachtet werden, dass eine SORTED oder HASHED Tabelle verwendet wird, um die größtmögliche Performance sicherstellen zu können.
Code:
SELECT * FROM ZTABLE INTO lt_cache. LOOP AT result_package ASSIGNING <RESULT_FIELDS>. READ TABLE lt_cache WITH TABLE KEY schluessel = <RESULT_ FIELDS >-schluessel INTO ls_cache BINARY SEARCH. MOVE-CORRESPONDING ls_cache INTO <RESULT_FIELDS>. ENDLOOP.
Stack
Werden dynamische Berechnungen oder Lookups, welche bei einer gewissen Anzahl von Datensätzen sich wiederholen, durchgeführt, macht es Sinn, diese nicht mehrmals auszuführen. Das Ergebnis wird in einem KEY à VALUE Modell abgespeichert, in unserem Fall eine SORTED Tabelle. Bei der DTP-Ausführung kann durch die geänderte Datenbankstruktur der HANA-Datenbank sowie durch die semantische Partitionierung eines DTP dafür gesorgt werden, dass gleichartige Datensätze innerhalb eines Pakets verarbeitet werden. Dieses Vorgehen optimiert den Stack-Cache ohne die Nutzung vom Shared Memory enorm.
Code:
LOOP AT result_package ASSIGNING <RESULT_ FIELDS >. READ lt_cache INTO ls_cache WITH KEY schluessel = <RESULT_FIELDS>-schluessel BINARY SEARCH. IF sy-subrc <> 0. SELECT * FROM ZTABLE INTO ls_cache WHERE schluessel = <RESULT_ FIELDS >-schluessel. INSERT ls_cache INTO lt_cache. ENDIF. MOVE-CORRESPONDING ls_cache INTO <RESULT_ FIELDS >. END LOOP.
Last Used
Die einfachste Form des Caching ist gut mit der semantischen Partitionierung zu nutzen. Diese liefert die markierten InfoObjekte sortiert und somit kann über eine einfache Struktur und einer Fallunterscheidung geprüft werden, ob die Struktur neu beladen werden muss. Als Beispiel können z.B. die Auftragspositionen nach den Aufträgen semantisch partitioniert abgefragt werden. Damit werden die Aufträge auch in den Start- und Endroutinen sortiert geliefert. Im ABAP kann nun einfach geprüft werden, ob die neue Zeile noch den gleichen Auftrag beinhaltet und ob eine Aktualisierung der Struktur erforderlich ist. Damit kann je nach Größe der Gruppierung die Anzahl der SQL Abfragen einfach aber stark verringert werden.
Code:
LOOP AT result_package ASSIGNING <RESULT_ FIELDS >. IF ls_cache- schluessel <> <RESULT_ FIELDS >-schluessel. SELECT * FROM ZTABLE INTO ls_cache WHERE schluessel = <RESULT_ FIELDS >- schluessel. ENDIF. MOVE-CORRESPONDING ls_cache INTO <RESULT_ FIELDS > END LOOP.
Vergleich der Ausführung ohne und mit Cache
Um zu veranschaulichen, wie sich die Verarbeitungslaufzeiten bei der Nutzung bzw. nicht Nutzung eines Caches unterscheiden, soll im folgenden Teil eine Ausführung mit unterschiedlichen Cache-Modellierungen durchgeführt und verglichen werden. Die Ausführung erfolgt dabei jeweils mit über 17.516.672 Datensätzen. Die Anzahl der gegen die HANA DB abgesetzten SQL Statements hat eine Paketgröße von 200.000 Datensätzen.
Um die Unterschiede in der Verarbeitungslaufzeit aufzuzeigen, wurden verschiedene mögliche Umsetzungen verglichen. Zur Ermittlung eines Startwertes wurde zunächst die Beladung ohne Ableitungen (einfache Transformation mit direkter Zuordnung) mit und ohne HANA Optimierung ausgeführt. Danach wurde noch ein Nachlesen mit einer SQL Abfrage pro Datenzeile und einmal mit einem einfachen "Full Table"-Cache pro Paket betrachtet (also ohne Shared Memory).
Die SAP HANA optimierte Ausführung mit Pushdown benötigt 2 Minuten und 9 Sekunden.
Die Ausführung ohne SAP HANA Optimierung benötigt bereits die dreifache Laufzeit, genau 6 Minuten und 11 Sekunden.
Die Ausführung mit einer SQL Abfrage pro Datenzeile (SELECT SINGLE) führt beinahe zu einer Verzehnfachung der Laufzeit des DTPs.
Ergebnis
Nun zum spannenden Ergebnis der Untersuchung: die Nutzung mit einem „Full Table“-Cache statt der vielfachen Ausführung eines SQL Statements ist wesentlich effektiver. D.h. pro Paket (mit einer Größe von 200.000 Zeilen) wurde nur eine SQL Abfrage benötigt, um eine interne Tabelle zu füllen. Die Laufzeit ist marginal höher, als die Ausführung ohne HANA Optimierung. Worin liegt dies nun begründet, dass es trotz der HANA In-Memory Verarbeitung zu einer so starken Diskrepanz kommt?
Vergleichen wir die Zugriffe auf die M-Tabelle, aus der wir Daten nachlesen, sieht man deutlich, dass jede Abfrage eine gewisse Grundlaufzeit besitzt. In dem Testfall sind dies ca. 300ms. Obwohl sich das erstmal nach sehr wenig anhört, ist genau diese Tatsache bei der millionenfachen Ausführung einer der entscheidenden Faktoren. Begründen lässt sich dies mit den normalen Latenzen, wie Netzwerk, ABAP Open SQL Abstraktion etc.
Die vereinfachte Laufzeitberechnung sieht dann folgendermaßen aus:
17.516.672 * 300ms / 3-fach parallele Ausführung = 29.19 Minuten Overhead für das Nachlesen, was in etwa auch der gemessenen Laufzeitsteigerung entspricht.
Schaut man sich das zweite Beispiel mit Cache an, ist sofort ersichtlich, dass mit 800ms die Abfragedauer etwas höher ist, die Ausführung jedoch nur paketweise erfolgt, also einmal auf 200.000 Zeilen. Die Verarbeitung in der internen Tabelle ist dann wieder enorm schnell und tritt nur marginal hervor.
Fazit
Somit ist deutlich zu erkennen, dass ein Cache in ABAP zu benutzen weiterhin Sinn ergibt. Vorteil ist jedoch, dass man komplexere mehrstufigere JOINs oder andere Logiken, bei denen die Verarbeitung in der Datenbank früher länger gedauert hat, nun einfach im SQL abbilden kann. Jedoch kommt es bei wiederkehrenden gleichartigen Abfragen zu einem organisatorischen Overhead, welcher sich in Summe doch bemerkbar macht.
Ab der Version 7.5 SP4 steigt die Anzahl der technischen Möglichkeiten weiter an. Es ist z.B. die kombinierte Nutzung von HANA optimierter Ausführung zusammen mit ABAP Ausführung möglich, wenn die beiden Transformationen durch eine InfoSource verbunden sind (partielle SAP HANA Ausführung). Details zu den Neuerungen erfahren Sie im Detail hier.
Zusammenfassend ergibt sich die Erkenntnis, dass weiterhin über die optimierte Ausführung von Ableitungen und Regeln nachgedacht und der richtige Ort für die Ausführung des Codes gesucht werden muss, selbst wenn ein Einsatz von HANA erfolgt. SAP wird mit der immer tieferen Integration von HANA ins SAP BW mit jedem Support Package weitere spannende Lösungen schaffen, worüber wir Sie in diesem Blog mit informieren werden.
Zusammenfassung der Laufzeiten
Ergänzung für Interessierte
„Full Table“-Cache Beispielcode
Anbei noch ein Codebeispiel, für einen „Full-Table“-Cache in vereinfachter Form. Generell empfiehlt sich Lookups in Klassen zu implementieren, da man diese für Testfälle auch einfach direkt ausführen kann und auch Erweiterungen einfacher zu implementieren sowie eine Share Memory Nutzung einfach möglich ist. Falls Sie Fragen haben, kommen Sie gerne auf mich zu.
„Full Table“-Cache Beispiel einer Formel-Routine: Globale Deklaration
„Full Table“-Cache Beispiel einer Formel-Routine: auszuführender Code