In dieser Serie wollen wir uns mit Implementierungstechniken für Lookups auseinandersetzen, bei denen jeder Datensatz der zu durchsuchenden Tabelle überprüft werden sollte. Je größer unsere Datenpakete und unsere Lookup-Tabellen, desto wichtiger ist eine performante Implementierung.
Weil man in BW-Transformationen normalerweise Datenpakete mit einer Größe von 50.000 oder mehr Datensätzen verarbeitet, ist es nicht zu empfehlen, einzelne SELECT-Anweisungen innerhalb der LOOP-Schleife in ABAP-Routinen durchzuführen. Dies würde dazu führen, dass für jeden Datensatz aus dem Datenpaket eine Datenbankselektion durchgeführt wird. Auch wenn man eine schnelle In-Memory-Datenbank wie SAP HANA hat, geschieht das Nachlesen von Millionen Datensätzen daraus nicht automatisch blitzschnell. Dies liegt auch an dem Overhead, der bei jedem einzelnen Zugriff entsteht. Besser ist es, vor der LOOP-Schleife der Transformation die relevanten Daten mit einer oder wenigen SELECT-Statements in internen Tabellen zu speichern und diese später mit der READ-Anweisung auszulesen. Am besten sollte man dafür Hash-Tabellen verwenden.
Ob man dann mehrere SELECT-Anweisungen pro Datenpaket (1) durchführt …
SELECT key_field1 key_field2 key_field3 group_field lookup_field FROM dbTab INTO TABLE itab_group1 FOR ALL ENTRIES IN result_package WHERE key_field1 = result_package-key_field1 AND key_field2 = result_package-key_field2 AND key_field3 = result_package-key_field3 AND group_field = 'GR1'.
"Bei Bedarf Sortierung/Aggregation/Reduktion der Felder on itab_group1 implementieren
SELECT key_field1 key_field2 key_field3 group_field lookup_field FROM dbTab INTO TABLE itab_group2 FOR ALL ENTRIES IN result_package WHERE key_field1 = result_package-key_field1 AND key_field2 = result_package-key_field2 AND key_field3 = result_package-key_field3 AND group_field = 'GR2'.
"Bei Bedarf Sortierung/Aggregation/Reduktion der Felder on itab_group1 implementieren
… oder eine SELECT-ENDSELECT-Schleife (2) nutzt, um mehrere interne Tabellen zu befüllen, ist an der Stelle für die Geschwindigkeit unerheblich.
SELECT key_field1 key_field2 key_field3 group_field lookup_field FROM dbTab INTO ls_all FOR ALL ENTRIES IN result_package WHERE key_field1 = result_package-key_field1 AND key_field2 = result_package-key_field2 AND key_field3 = result_package-key_field3 AND ( group_field = 'GR1' OR group_field = 'GR2') AND NOT lookup_date = '00000000'. CASE ls_rest_plus-group_field. WHEN 'GR1'. IF itab_group1 IS INITIAL.
"Ab diesem Punkt ist das Feld mit der Gruppe nicht mehr wichtig => ergo geben wir nur die restlichen Zeilen weiter
MOVE-CORRESPONDING ls_all TO ls_group. INSERT ls_group INTO TABLE itab_group1. ELSE. READ TABLE itab_group1 WITH TABLE KEY key_field1 = ls_group-key_field1 key_field2 = ls_group-key_field2 key_field3 = ls_group-key_field3 ASSIGNING <fs_group>. IF sy-subrc = 0.
"Bei Bedarf Aktualisierung der Zeile von itab_group1 implementieren
ELSE. MOVE-CORRESPONDING ls_all TO ls_group. INSERT ls_group INTO TABLE itab_group1. ENDIF. ENDIF. WHEN OTHERS.
"Wie oben, aber für itab_group2
ENDCASE. CLEAR ls_all. CLEAR ls_group. UNASSIGN <fs_group>. ENDSELECT.
Bei einem DTP mit Paketgröße 200.000 und knapp 16 Mio. zu beladenden Datensätzen haben wir mit (1) 43 m 39 s und mit (2) 42 m 25 s gebraucht. Dabei haben wir aus einer Tabelle mit knapp 190 Mio. Datensätzen nachgelesen und müssten insgesamt 5 Gruppen von Daten in internen Tabellen aufbauen, die beim Lookup in der LOOP-Schleife der Transformation durchgesucht werden mussten. Und ja, diese Beladungen wurden auf BW on HANA durchgeführt.
Zum Vergleich, wenn wir an der Stelle bei den 5 Lookups innerhalb der LOOP-Schleife aus der Datenbank nachlesen würden, würden wir für die Beladung derselben Datenmenge ca. 5 Stunden verbrauchen.
Dass die Methoden (1) und (2) vergleichbar schnell laufen, bestätigt auch die These (Kapitel 4.4.2), dass der gängige schlechte Ruf von SELECT-ENDSELECT-Schleifen nicht gerechtfertigt ist. Diese haben zwar gewisse Nachteile, performancetechnisch sind sie aber nicht unbedingt langsamer als SELECT-INTO-Statements. Vor allem, wenn man dadurch eine einfachere und besser nachvollziehbare Programmierlogik aufbauen kann, sollten diese bevorzugt werden. Bei In-Memory-Datenbanken werden die Nachteile von SELECT-ENDSELECT-Schleifen irrelevanter.
Wenn man auch noch darauf achtet, nur die Datensätze und Felder zu selektieren, die man später benötigt, kann man sich in der Regel auch auf performante Transformationen freuen. Der Implementierungsaufwand an der Stelle lohnt sich!