Hervorgehoben

Erster SQLScript Videokurs verfügbar

Seit Anfang August ist auf unserer Seite www.brandeis-training.de der erste Videokurs „SQLScript Grundlagen“ verfügbar.

Dieser Videokurs ist als vollwertige Schulung konzipiert und entspricht Inhaltlich meinen bewährten Firmenschulungen SQLScript bzw. dem ersten Teil des Kurses SQLScript für BW-Berater.

Lernen Sie die Grundlagen der Sprache SQLScript, dem SQL-Dialekt für die SAP HANA Datenbank, und die zugehörigen Werkzeuge zur Programmierung kennen.

Dieser Kurs fokusiert sich auf die deklarativen Aspekte der Abfragesprache SQLScript. Sie lernen, wie Sie performante Abfragen auf der SAP HANA Datenbank erstellen und testen können. Dazu lernen Sie die notwendigen Werkzeuge wie die Web-Based Development Workbench und die SQL-Konsole kennen.

Sie erhalten 3 Monate Zugriff auf den Kurs mit allen Videos und Übungen. In diesem Zeitraum können Sie für Fragen auch eine Sprechstunde vereinbaren und jederzeit über das Supportportal Unterstützung zu konkreten Problemen anfordern. 

Der Kurs ist in 4 Wochenabschnitte mit jeweils ca. 4 Stunden Lernaufwand eingeteilt. Alle Inhalte sind aber sofort nach der Buchung verfügbar.

Nach Abschluss aller Lektionen und dem Bestehen des Abschlusstests erhalten Sie ein Zertifikat, dass die erfolgreiche Teilnahme bestätigt. 

Warum sind skalare UDFs so langsam?

Beim Laden von Daten aus Quellsystemen gibt es im SAP BW Anforderungen, die sich auf Feldebene häufig wiederholen. Dazu gehören vor allem Logiken zum Bereinigen und Aufbereiten der Daten, wie zum Beispiel:

  • Hinzufügen und entfernen von führende Nullen
  • Fallunterscheidungen
  • Entfernen von Leerzeichen am Anfang oder Ende
  • Konvertierung in Großbuchstaben
  • Ableiten eines Feldes aus einem anderen mit Substrings nach festem Muster, z.B. COAREA ==> COUNTRY
  • Ableiten von Zeitmerkmalen

Das folgende Listing zeigt ein paar Beispiele im Quellcode:

outTab = SELECT TO_VARCHAR(TO_DATE(calday), 'YYYYMM') AS calmonth,
				"/BIC/SRCSYS",
				...
				"/BIC/CURTYP",
				LEFT("/BIC/COAREA", 2) AS "/BIC/COUNTRY",
				SUBSTRING("/BIC/BI_PROFCT", 9, 2) as "/BIC/PCACCID",
				CASE SUBSTRING("/BIC/PROFCT", 8, 3)
				  when '643' then '1' 
				  when '655' then '1'
				  when '641' then '2' 
				  when '651' then '2'
				  when '643' then '3' 
				  when '655' then '3'
				  else ''
				end as  "/BIC/PRBY',
				...
		   FROM :intab;

Typische Ausdrücke in der Feldliste einer Transformationsroutine

Allen diesen Anforderung ist gemein, dass sie

  • sich in SQLScript mit den vorhandenen SQL-Funktionen einfach implementieren lassen
  • sich oft wiederholen
  • von der SAP HANA sehr schnell ausgeführt werden können, solange sie direkt in der Transformationsroutinen implementiert sind.

DRY – Don’t Repeat Yourself

Das bekannte DRY Prinzip sollte hier eigentlich zum Tragen kommen. Also das man den Quelltext nicht ständig wiederholt. In der Feldliste bieten sich hierfür die skalaren, Benutzerdefinierten Funktionen (UDF) an. Diese waren bis vor Kurzem kein Thema für die Transformationsroutinen im BW, weil diese erst seit AS ABAP Release 753 mit dem AMDP Framework erstellt werden können [1]SAP Dokumentation zu AMDP Funktionen. Aber genau für die genannten Anforderungen wären skalare UDFs eigentlich ideal. Damit kann man eine einheitliche Implementierung gewährleisten. Und man kommt im Quelltext von einer technischen Beschreibung der Ausdrücke zu einer fachlichen Sicht:

outTab = SELECT "ZCL_CALDAY=>TO_CALMONTH"(calday) AS calday
				"/BIC/SRCSYS",
				...
				"/BIC/CURTYP",
				"ZCL_COAREA=>TO_COUNTRY"("/BIC/COAREA") AS "/BIC/COUNTRY",
				"ZCL_PROFCT=>TO_PCACCID"(/BIC/PROFCT") as "/BIC/PCACCID",
				"ZCL_PROFCT=>TO_PRBY"(/BIC/PROFCT") as "/BIC/PRBY',
				...
		   FROM :intab;

Auslagern der Ausdrücke in eine skalare UDF

Die ausgelagerten Funktionen sehen sehr viel eleganter aus. Und auch unter dem Aspekt der Wartung sind sie haushoch überlegen. Wenn beispielsweise ein weiteres Profitcenter in der Liste auftaucht, dann gibt es genau eine Funktion, die man anpassen muss. Am Beispiel von ZCL_PROFCT=>TO_PRBY zeige ich eine solche skalare AMDP Funktion:

CLASS zcl_profct DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_amdp_marker_hdb.
    METHODS to_prby IMPORTING VALUE(iv_profct) TYPE char10
                    RETURNING VALUE(rv_prby)   TYPE char1.
ENDCLASS.

CLASS zcl_profct IMPLEMENTATION.
  METHOD to_prby BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS DETERMINISTIC READ-ONLY.
    rv_prby = case SUBSTRING(:iv_profct, 8, 3)
                  WHEN '643' then '1'
                  WHEN '655' then '1'
                  WHEN '641' then '2'
                  WHEN '651' then '2'
                  WHEN '643' then '3'
                  WHEN '655' then '3'
                  ELSE ''
                END ;
  ENDMETHOD.

ENDCLASS.

An dem Beispiel sieht man gut, dass die Funktion nur eine einfache „Hülle“ für einen CASE-Ausdruck ist. Die Auslagerung in die ABAP Welt ermöglicht übrigens auch, ganz einfach UnitTests für die Funktionen zu schreiben. Da die Funktionen in der Datenbank erst beim ersten Aufruf aus dem ABAP generiert werden, bieten sich UnitTests auch dafür an. [2]Ich verwende bewusst keine von BW-InfoObjects generierten Datenelemente, damit die Abhängigkeit so gering wie möglich ist.

Elegant, aber langsam

So elegant die Auslagerung von Logik in UDFs auch ist, für große Datenmengen ist das Konzept leider nicht zu gebrauchen. Denn die UDFs beeinflussen die Laufzeit erheblich. Das möchte ich an einem anderen Ausdruck aus dem obigen Beispiel zeigen:

TO_VARCHAR(TO_DATE(calday), 'YYYYMM')

Dieser einfache Ausdruck wandelt ein ABAP DATS Wert in ein SQLScript Datum, dass dann wiederum in eine Zeichenkette im Format YYYYMM ausgegeben wird. Dieses entspricht dem Format des beliebten InfoObject CALMONTH.

Beispiel: 20200928 ==> 202009

Dafür legen ich nach dem obigen Muster eine AMDP UDF an:

  METHOD to_calmonth BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS DETERMINISTIC READ-ONLY.
    rv_result = TO_VARCHAR(TO_DATE(:iv_calday), 'YYYYMM');
  ENDMETHOD.

Ich habe zwei Abfragen in der SQL-Konsole auf eine kleine BW-Tabelle mit ca. 3 Mio Einträgen gemacht: Einmal direkt mit dem Ausdruck und einmal mit dem Funktionsaufruf.

Ohne UDF

do begin
	select budat, 
	       TO_VARCHAR(TO_DATE(budat), 'YYYYMM'),
	       account, 
	       amount, 
	       curr
	       from "/BIC/AZBR_E1_S2";     
end;

Konsole

Statement 'do begin select budat, "ZCL_CALDAY=>TO_CALMONTH"(BUDAT), account, amount, curr from ...' 
successfully executed in 2:09.418 minutes  (server processing time: 4:18.632 minutes)
Fetched 1000 row(s) in 103 ms 144 µs (server processing time: 0 ms 675 µs)
Result limited to 1000 row(s) due to value configured in the Preferences

Mit UDF

do begin
	select budat, 
	       "ZCL_CALDAY=>TO_CALMONTH"(BUDAT),
	       account, 
	       amount, 
	       curr
	       from "/BIC/AZBR_E1_S2";     
end;

Konsole

Statement 'do begin select budat, TO_VARCHAR(TO_DATE(budat), 'YYYYMM'), account, amount, curr from ...' 
successfully executed in 501 ms 237 µs  (server processing time: 801 ms 664 µs)
Fetched 1000 row(s) in 102 ms 468 µs (server processing time: 0 ms 677 µs)
Result limited to 1000 row(s) due to value configured in the Preferences

Die Laufzeiten sind dermaßen unterschiedlich, dass man eigentlich von einem Bug ausgehen muss. Denn die Komplexität bei dem Besipiel ist minimal. Mit weniger Komplexität brauche ich auch keine UDF mehr. Was ich erstaunlich finde:

  • Tatsächlich stehen in der Tabelle nur 365 unterschiedliche Werte von BUDAT drin. Damit hat das System die Information: Bei gleicher Eingabe sollte auch das gleiche Ergebnis geliefert werden. Siehe [3]SAP Dokumentation zur CREATE FUNCTION Anweisung . Damit sollte sie maximal 365 Mal ausgeführt werden und danach aus dem Puffer gelesen werden, oder?
  • Ich hätte auch erwartet, dass eigentlich nur das Wörterbuch der Spalte konvertiert wird, also jeder Wert genau ein Mal.
  • Wenn man mit einem primitiven Texteditor mit einfachem Suchen / Ersetzen den Funktionsaufruf durch den Funktionsinhalt ausgetauscht hätte, ist man über 100 x schneller. Das sollte der Optimizer einer SAP HANA 7[4]Scalar User Defined Functions in SAP HANA – Der erste Blog Beitrag zu dem Thema von Rich Heilmann von 2013 Jahre nach der Einführung skalarer UDFs doch hinbekommen, oder?

Um das ganze vollständig zu dokumentieren, habe ich auch noch die Analyse mit PlanViz gemacht.

PlanViz der Abfrage mit Ausdruck
PlanViz der Aubfrage mit UDF

Es ist gut sichtbar, dass im Großen und Ganzen der gleiche Ausführungsplan gewählt wird. Aber die Laufzeit des einen, rot markierten JECalculate Knoten enthält die gesamte Laufzeit für die UDF Aufruf. Das müsste sich doch zumindest parallelisieren lassen.

Warum ist das so? Habe ich einen Denkfehler in meinem Beispiel? Kann ich das noch optimieren? Oder sind die UDFs einfach so langsam. Bei der Recherche in Foren habe ich gesehen, dass ich mit meinen Problemen nicht alleine bin. Es gibt auch mehrere Möglichkeiten, mit ungünstigen Funktionen das System auszubremsen. [5]Beispiele für ungünstige UDF Funktion im Speicherproblem[6]Mehrfacher Aufruf skalarer UDFs mit mehreren Rückgabeparametern[7]Keine parallele Ausführung von mehreren UDFs

Es besteht auf jeden Fall noch großes Potenzial. Zumindest für einfach Ausdrücke ohne Abfragen auf andere DB-Tabellen.
Mir ist klar, dass es auch komplexe Anforderungen gibt, die sich nicht auf einen einzigen Ausdruck reduzieren lassen. Aber dann wäre zumindest eine parallele Verarbeitung wünschenswert.

Update vom 8.10.2020: Ich habe mich heute noch etwas mit dem Thema Performanceoptimierung beschäftigt. Dabei bin ich auch über die HINTS gestolpert. Mit dem HINT(INLINE) soll eigentlich genau das gewünschte Verhalten ausgelöst werden: Die Optimierung sollte global erfolgen. Aber leider steht in der Dokumentation nichts über Funktionen. Alles bezieht sich auf Prozeduren. Und das entspricht auch meiner Beobachtung: Der Hint bringt absolut keine eränderung . Es bleibt langsam.

do begin
    select budat, 
           "ZCL_CALDAY=>TO_CALMONTH"(BUDAT),
           account, 
           amount, 
           curr
           from "/BIC/AZBR_E1_S2"
           WITH HINT(INLINE);     
end;

Anmerkungen und Verweise   [ + ]

1. SAP Dokumentation zu AMDP Funktionen
2. Ich verwende bewusst keine von BW-InfoObjects generierten Datenelemente, damit die Abhängigkeit so gering wie möglich ist.
3. SAP Dokumentation zur CREATE FUNCTION Anweisung
4. Scalar User Defined Functions in SAP HANA – Der erste Blog Beitrag zu dem Thema von Rich Heilmann von 2013
5. Beispiele für ungünstige UDF Funktion im Speicherproblem
6. Mehrfacher Aufruf skalarer UDFs mit mehreren Rückgabeparametern
7. Keine parallele Ausführung von mehreren UDFs

Ist das SQLScript der SAP HANA Cloud abwärtskompatibel?

Bislang hatte ich mir nie Gedanken über die Kompatibilität von SAP HANA Cloud und HANA 2.0 gemacht. Die Abwärtskompatibilität von ABAP ist legendär, da konnte man sich schon immer auf die SAP verlassen. Beim Ausführen der Installationsskripte für das Demo Datenmodell meines Buches ist aber einem aufmerksamen Leser aufgefallen, dass dies in der SQL-Konsole des Database Explorers der SAP HANA Cloud einen Fehler produziert:

Fehlermeldung beim Ausführen des Installationsskripts Nr. 4

Also habe ich mich auf die Suche nach Informationen über die Kompatibilität zwischen SAP HANA 2.0 und SAP HANA Cloud Systemen in Bezug auf SQLScript begeben. Der zentrale Hinweis zu diesem Thema ist 2868742 – Unterschiede zwischen SAP HANA Cloud und SAP-HANA-Plattform für SQL, SQLScript und SAP HDI (SAP HANA Deployment Infrastructure) Der Grund für die Inkompatibilitäten ist angeblich die Speicheroptimierung der Cloud Version von SAP HANA, weshalb manche unwichtigen Features entfernt wurden. Konkrete Unterschiede werden in dem Hinweis nicht genannt, aber die entsprechenden Stellen in der SAP Dokumentation sind verlinkt. Für den Bereich SQL und SQLScript ist die Seite SQL and SQLScript Compatibility des Dokuments SAP HANA Cloud Compatibility Reference verlinkt.

Hier werden alle Features aufgelistet, die nicht mehr unterstützt werden. Die Liste ist erschreckend lang, aber das meiste davon ist für Anwendungsentwickler eher nicht so wichtig. In erster Linie werden DDL und DCL Anweisungen genannt. Der Sprachfeatures, die im Bereich DML und SQLScript allgemein wegfallen, ist relativ übersichtlich. Ich habe hier eine Zusammenfassung erstellt:

  • CE-Funktionen dürfen nicht mehr verwendet werden. Das ist überfällig, nach dem John Appleby schon 2014 einen lesenswerten Nachruf darauf geschrieben hat: Calculation Engine (CE) Functions – Rest in Peace
  • CREATE <user_defined_function_type> FUNCTION – Das muss wohl eine versteckte Syntax sein, denn in der Referenzdokumentation ist diese Variante nicht zu finden.
  • CREATE PROCEDURE … LANGUAGE RLANG – OK, Keine R-Funktionen mehr
  • CREATE PROCEDURE … WITH RESULT VIEW – Statt dessen können Table Functions verwendet werden
  • CALL <Procedure> … WITH VERSION VALIDATION
  • CALL <Procedure> … WITH OVERVIEW
  • SQL-Funktion LANGUAGE(<Text>)
  • Datentyp VARCHAR ist jetzt nur noch als Alias für NVARCHAR verwendet! Gleiches gilt für die Datentypen CLOB und CHAR.
  • SELECT … FROM <Hierarchy Column View>
  • SELECT … WHERE CONTAINS … LINGUISTIC
  • SELECT … WHERE CONTAINS … FULLTEXT( { ON | OFF | AUTOMATIC })
  • SELECT … GROUP BY { GROUPING SETS | ROLLUP | CUBE } TEXT_FILTER <Filter> FILL UP SORT MATCHES TO TOP.
  • SELECT … AS OF { COMMIT ID | UTCTIMESTAMP }
  • SELECT … WITH RANGE_RESTRICTION
  • SELECT … WITH HINT ( ) use in subqueries
  • SELECT … WITH DATAPROVISIONING PARAMETERS

Allerdings habe ich in diesen Dokumenten keinen Hinweis darauf gefunden, warum die UPDATE FROM Anweisung nicht unterstützt wird. Auch SAP Hinweis 2241598 – Changed UPDATE FROM syntax can cause ‘invalid table name’ error konnte nicht helfen, obwohl der den Themenbereich betrifft. Vielleicht liegt es aber auch nicht an der Kompatibilität der SAP HANA Cloud, sondern an dem Database Explorer. Hier der Code dazu, vielleicht hat ja irgendwer einen Vorschlag dazu:

	UPDATE tasks
       SET create_date = datum
      FROM :lt_dates AS dates,
		    tasks
      WHERE tasks.id = dates.id;

Das Installationsskript wurde natürlich umgehend aktualisiert, so das es sich jetzt in jeder mir bekannten HANA SQL-Konsole ausführen lässt.

Und noch etwas habe ich gefunden: Statt dem DB-Benutzer SYSTEM soll jetzt der DBADMIN verwendet werden.

Ein Framework für alle Anforderungen im BW Transformationsroutinen

In dieser Beitragsserie geht es ausnahmsweise nicht um SQLScript, sondern um primär um ABAP. Die Transformationsroutinen im SAP BW lassen sich ja in beiden Programmiersprachen implementieren. Und es gab und gibt viele Kunden, die ABAP gerne dafür Einsetzen. Dafür gibt es unterschiedliche Gründe. Eine große Stärke von ABAP ist die dynamische Verwendung, die ich in dieser Form mit SQLScript nicht erreichen kann.

Ich möchte in dieser Serie meine Erfahrungen aus meinen letzten BW Projekte veröffentlichen. Ich hatte immer wieder das Glück, dass ich in Greenfield Projekten bei sehr großen Kunden mit hohen Anforderungen an das SAP BW und insbesondere an die Backend Verarbeitung arbeiten durfte. Das ist für mich als Berater mit einem Fokus auf Softwareentwicklung und starkem BW und HANA Wissen natürlich ideal.

Die Probleme in BW Transformationsroutinen

In den über viele, teilweise über mehr als 10 Jahren, gewachsenen SAP BW-Systemen findet man häufig eine große Bandbreite von unterschiedlichen BW-Transformationsroutinen. Manche davon sind sehr sauber und effizient programmiert. Andere sind kaum mehr wartbar oder haben massive Performance Probleme. Ein paar typische Fälle, die wahrscheinlich die meisten schon mal gesehen haben, möchte ich hier vorstellen.

Der Spaghetti LOOP

Unstrukturierten bzw. schlecht strukturierten Code bezeichnet man als Spaghetticode [1]https://de.wikipedia.org/wiki/Spaghetticode. Mit der Länge des Codeabschnitts nimmt die Lesbarkeit erheblich ab. Das Problem wird in Transformationsroutinen dadurch verstärkt, dass diese normalerweise aus einem großen LOOP über dem ResultPackage[2]Ich schreibe ResultPackage, weil es der meiste Fall ist. Je nach Routinentyp kann natürlich auch das SourcePackage gemeint sein bestehen. Diese unheilvolle Kombination nenne ich Spaghetti LOOP. Ein typisches Problem hierin ist beispielsweise, das Werte aus einem vorherigen Schleifendurchlauf in Variablen abgespeichert und in späteren Durchläufen wieder verwendet werden. Das bedeutet, dass ich stets den Code vor und nach der aktuellen Zeile durchsuchen muss, ob eine Variable verändert wird.

Ich habe schon Spaghetti LOOPs über mehr als 2000 Zeilen gesehen und sie haben die Fehlersuche und die Bearbeitung von neuen Anforderungen fast zum Erliegen gebracht. Weil jede Korrektur unvorhersehbare Auswirkungen auf die anderen Anforderungen hervorgebracht hat.

50 shades of modularisation

Es gibt in ABAP leider sehr viele unterschiedliche Möglichkeiten, wie man vermeiden kann, dass der ganze Code komplett in der Transformationsroutine landet. Leider werden auch alle dieser Modularisierungstechniken verwendet:

  • Instanzmethoden
  • Klassenmethoden
  • Funktionsbausteinen
  • Unterprogrammen
  • Makros
  • Includes (!)

Ich habe tatsächlich schon Transformationsroutinen gesehen, die nur aus einem INCLUDE Anweisung bestanden. Das gleiche Include wurde dann in unterschiedlichen Routinen genutzt. Das war die hässlichste Anwendung des DRY[3]Don’t Repeat Yourself Prinzips, die ich je gesehen hatte.

Performanceprobleme

Generic Overengineering

Generische und dynamische Programmierung ist in ABAP sehr gut möglich. Damit kann man sehr nützliche Sachen machen, aber man kann auch einfache Anforderungen extrem verkomplizieren. Die Les- und Wartbarkeit des Codes leiden dann darunter. Und häufig sieht man, dass die gleiche generische Funktion mehrfach von unterschiedlichen Entwicklern erfunden wurde. Oder dass generische Funktionen nur genau einmal aufgerufen werden.

TYPE STANDARD TABLE und ASSIGN

Die Auslagerung von Code aus den Transformationsroutinen bringt ein Typisierungsproblem mit sich. Der Type des ResultPackage wird in der Routinenklasse generiert. Deshalb wird in der Signatur von Methoden typischerweise mit TYPE STANDARD TABLE gearbeitet. Der Zugriff auf die Zeilen der Tabelle erfolgt dann mit LOOP ASSIGNING und der Zugriff auf die Felder der Zeilen auch wieder dynamisch mit ASSIGN. Mit den Feldsymbolen können wir dann direkt in die Tabelle in der aktuellen Zeile/Spalte schreiben. Das ist praktisch, erlaubt aber auch die Veränderung von Feldern, die wir ursprünglich nur lesen wollten. Es fehlt also eine saubere Dokumentation, was gelesen und was verändert wird. Und der Code für jedes verwendete Feld ist relativ lang (und langsam):

FIELD-SYMBOL <lv_value> TYPE ..
ASSIGN COMPONENT 'FELDNAME' 
    OF STRUCTURE <resultline>
     TO <lv_value>. 
ASSERT <lv_value> IS ASSIGNED. 

Das kann man schöner machen.

Die Ursachen

Für diese (und andere) Probleme gibt es mehrere Ursachen, die man in Projekten immer wieder beobachtet.

Gelegenheitsprogrammierer

Fast immer werden die Transformationsroutinen von BW-Beratern[4]Der Begriff Gelegenheitsprogrammierer klingt sehr negativ, er soll aber nicht die Arbeit der Kollegen abwerten. Die meisten BW-Berater sind sehr kompetent und erfahren und ich habe großen Respekt vor Ihrer Arbeit. Aber als Entwickler, die sich 8 Stunden am Tag mit ABAP auseinandersetzen, habe ich eine anderes Verständnis für die Programmierung als ein typischer BW-Berater. entwickelt, die nur begrenzt Programmiererfahrungen haben. Das reicht auch, um vielleicht für 70% der Anforderungen eine ausreichende Lösung zu finden. Aber wenn es dann komplexer wird, sind fundierte ABAP und Programmierkenntnisse gefragt. Die erlernt man nicht nebenbei, sondern dann braucht es einen erfahrenen Programmierer.

Manchmal überschätzen sich auch BW-Berater und versuchen es einfach. Und manchmal führt das auch zu einer mehr oder weniger lauffähigen Lösung. Aber in Bezug auf Wartbarkeit sieht es dann ganz schlecht aus.

ERP ABAP Entwickler

Falls die BW-Berater scheitern, kommt es häufig zur nächsten Ursache von Problemen: ERP ABAP Entwickler sind es nicht gewöhnt, mit echten Massendaten zu arbeiten. Darum werden zwar lauffähige, saubere, wartbare, aber langsame Konzepte auf Zeilenebene umgesetzt.

Bewegliche Ziele

Häufig sind die Anforderungen nicht von Anfang an klar. Zum einen verändern sich die Anforderungen und zum anderen kommt immer wieder was neues hinzu. Diese Veränderungen werden immer in den bestehenden Code eingewoben. Das passiert auch dann, wenn der bestehende Code nicht mehr 100% verstanden wird.

Viele Köche

Durch lange Softwarelebenszyklen und lange Projekte ergibt sich das nächste Problem. Da in einem BW laufend weiter entwickelt wird, sind im Laufe der Zeit viele unterschiedliche Personen daran beteiligt. Damit wird das Rad immer wieder neu erfunden, und die Anzahl der Variationen nimmt zu. Für die komplexen Transformationen aus den ersten Tagen findet sich selten ein echter Experte.

Keine modernen Konzepte und Methoden

In der SAP Welt setzen sich moderne Konzepte und Methoden zum Entwickeln von Software langsamer durch, als das in anderen Gebieten der Fall ist. Dazu gehören unter anderem:

  • Test Driven Development (TDD)[5]https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung
  • Clean Code [6]https://de.wikipedia.org/wiki/Clean_Code

Das gilt in besonderem Maße für BW-Transformationsentwicklung. Zum einen, wegen der oben unter genannten Aspekte. Zum anderen auch, weil die Anforderungen häufig unterschätzt werden, nach dem Motto: Für die kleine Routine lohnt sich das doch gar nicht.

Auch ist die Anwendung von TDD erschwert, wenn man gegen den Datenbankzustand programmieren muss. Das ist aber im BW leider der Fall.

Das Transformationsframework

Wir haben schon in unterschiedlichen Projekten die Transformationsroutinen in eine saubere Struktur gebracht. Dabei hilft ein Framework, das ein sauberes und einheitliches Vorgehen erzwingt.

Der wichtigste Punkt ist, dass die Komplexität der Anforderungen in kleine, einfache Schritte zerlegt wird. Und dass jeder dieser Schritte in einer separaten Methode implementiert wird. Manche dieser Schritte können generisch implementiert sein und lassen sich in unterschiedlichen Datenmodellen immer wieder verwenden. Andere Schritte sind konkret genau nur für eine Transformation notwendig.

Diese Zerlegung ermöglicht es, dass wir zum einen die Steuerung der Schritte und die Parametrisierung auslagern. Also eine Trennung zwischen:

  1. Was soll gemacht werden
    1. Welche Schritte in welcher Reihenfolge
    2. Welche Felder werden in einem Schritt gelesen, welche verändert
    3. (Welche Datensätze sollen in einem Schritt verändert werden?)
  2. Wie soll der Schritt implementiert werden.

Durch die Zerlegung in kleine Schritte und die Auslagerung der Steuerung dieser Schritte lassen sich viele orthogonale Anforderungen implementieren. Unter anderem:

  • Laufzeitmessung pro Schritt
  • Generierung einer Dokumentation
  • Gezielte Breakpoints vor einem Schritt
  • Test Driven Development
  • Wiederverwendbarkeit von Schritten
  • Generierung von AMDP Code

In den folgenden Blogposts:

  • Die Zerlegung in Schritte – Das sieht zunächst so aus, als ob da viel Overhead dazu kommt. Das ist aber Quatsch. Laufzeit und Wartbarkeit verbessern sich, auch wenn es etwas mehr Quelltext wird.
  • Die Steuerung des Ganzen – Ein Tabellenwerk, mit dem man die Transformationen und die wichtigen Parameter der Schritte beschriebt.
  • Fehlerverarbeitung
  • Neue Felder braucht das Land – damit sich die Anforderungen in kleine Schrittte zerlegen lassen, müssen wir teilweise noch zusätzliche Felder in unser ResultPackage einbaueh

Anmerkungen und Verweise   [ + ]

1. https://de.wikipedia.org/wiki/Spaghetticode
2. Ich schreibe ResultPackage, weil es der meiste Fall ist. Je nach Routinentyp kann natürlich auch das SourcePackage gemeint sein
3. Don’t Repeat Yourself
4. Der Begriff Gelegenheitsprogrammierer klingt sehr negativ, er soll aber nicht die Arbeit der Kollegen abwerten. Die meisten BW-Berater sind sehr kompetent und erfahren und ich habe großen Respekt vor Ihrer Arbeit. Aber als Entwickler, die sich 8 Stunden am Tag mit ABAP auseinandersetzen, habe ich eine anderes Verständnis für die Programmierung als ein typischer BW-Berater.
5. https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung
6. https://de.wikipedia.org/wiki/Clean_Code

Neo Umgebung wird abgeschaltet

Die Neo Umgebung der SAP Cloud Platform wird am 14. November abgeschaltet! Damit verschwinden auch eine gerne genutzte Möglichkeit, sich ganz einfach eine HANA Instanz mit SQL-Konsole anzulegen…

Nächste Woche folgt ein Blogpost, wie man das auch in der Cloud Foundry Umgebung erreichen kann.
Der E-Learning Kurs SQLScript Grundlagen auf https://www.brandeis-training.de wird dann ebenfalls entsprechend aktualisiert.

Lizenzschlüssel für CAL Developer System A4H erneuern

Jeder, der ein BW/4HANA Entwicklersystem in der SAP Cloud Appliance Library betreibt, kennt das Problem: Wenn man vergisst, rechtzeitig die Lizenz einzuspielen (SAP Hinweis 1644792, SAP Doku), dann ist das System nicht mehr erreichbar und die Datenbank geht in den Lockdown Modus (SAP Hinweis 2678651).

Wenn man die HANA und den A4H Lizenzschlüssel rechtzeitig einspielt, ist das aber relativ kleines Problem und in 5 Minuten erledigt. Wichtig ist: Sowohl BW/4HANA als auch SAP HANA benötigen eine Lizenz. Leider ist in der Anleitung der SAP hierzu ein wichtiges Detail vergessen worden: Man muss sich auf der HANA mit der Systemdatenbank und nicht mit dem A4H Tenant verbinden. Häufig ist für die Systemdatenbank noch kein eigenes System in Eclipse angelegt. Das geht mit den folgenden Parametern:

Parameter zum Anlegen eines Systems für die Systemdatenbank

In dem Beispiel ist der Hostname in der etc/hosts Datei bereits auf die IP gemappt. Alternativ müsst Ihr die IP-Adresse nehmen.

Benötigte Zeit: 5 Minuten.

HANA & BW Lizenz erneuern

  1. In Eclipse mit der Systemdatenbank mit dem Benutzer SYSTEM verbinden

    Das ist die Verbindung SYSTEMDB@HDB (SYSTEM) !

  2. HANA Hardware Key kopieren

    Unter den Properties im Bereich License den Hardware Key markieren und in die Zwischenablage legen.

  3. HANA Lizenzschlüssel generieren lassen

    Auf der folgenden Website die notwendigen Informationen eintrage: https://go.support.sap.com/minisap/#/minisap
    Für die HANA Lizenz unter dem BW/4HANA System müsst Ihr die Option
    HDB - SAP HANA Platform Edition (64GB)
    ankreuzen. Das kann sich aber ändern und die korrekte Bezeichnung sollte im „Getting Started Guide“ für Eure Lösung stehen.

  4. Alte HANA Lizenz Löschen und neue HANA Lizenz einspielen

    Siehe Abbildung von Schritt 3.
    Falls die Buttons „Delete License Key“ und „Install License Key“ ausgegraut und inaktiv sind, bitte noch mal prüfen, dass Ihr tatsächlich mit der Systemdatenbank verbunden seid!
    Erst Löschen der Lizenz, dann die im vorigen Schritt runtergeladene Lizenz hochladen.

  5. BW-Lizenz erneuern

    Jetzt wird in die SAP GUI gewechselt. Dazu im SAP Logon mit SAP* im Mandanten 000 anmelden mit dem Standardkennwort.

  6. Transaktion SLICENSE aufrufen

    Und den „Active Hardware Key“ in die Zwischenablage

  7. A4H Lizenzschlüssel für das BW erzeugen

    Wie in Schritt 3, nur dieses Mal mit dem anderen Hardware Key und dem System A4H. Es wird eine Datei A4H_Multiple.txt erzeugt.

  8. Alte Lizenzen Löschen und neue einspielen

    Wieder zurück in die SAP GUI, rechtsklick auf die alten Lizenzen und „Delete license“ auswählen. Wenn beide Lizenzen weg sind, auf Install klicken und die Datei A4H_Multiple.txt aus dem vorherigen Schritt hochladen.

  9. Transaktion SECSTORE aufrufen

    In der Anleitung der SAP ist erwähnt, dass man noch die Transaktion SECSTORE aufrufen soll und dort mit F8 alle Einträge prüfen soll. Das funktioniert bei mir prima, aber leider ist nicht erwähnt, was man machensoll, wenn die Prüfungen scheitern. 😉

Das war die Anleitung. Vor allem habe ich sie für mich aufgeschrieben, da ich immer mal wieder an den gleichen Hürden hänge. Ich freue mich aber auch über Anregungen und Feedback meiner Leser.

DML Tabellenvariablen in SQLScript

Mit dem Konzept der DML Tabellenvariablen hat die SAP die bisherigen Konzepte zum ändernden Zugriff auf Tabellenvariablen in SQLScript sinnvoll Ergänzt. Der Indexbasierte Zugriff und die Änderungsoperatoren waren sperrig und erforderten eine Menge imperativem Quellcode, um keine Änderungen in einer Tabelle zu machen. Das ist mit dem letzten SPS besser geworden, da hier Tabellenvariablen eingeführt wurden, die sich mit den normalen SQL Anweisungen bearbeiten lassen. In der 2. Auflage meines Buches habe ich darüber ein kleines Kapitel geschrieben:

DML Tabellenvariablen in SQLScript

Mit SP04 für SAP HANA 2.0 ist die Verwendung der Data-Manipulation-Language-Anweisungen (DML-Anweisungen) INSERT, UPDATE und DELETE, die normalerweise für Datenbanktabellen verwendet werden, auch für Tabellenvariablen möglich. Um in den Anweisungen zwischen Datenbanktabellen und Tabellenvariablen zu unterscheiden, muss Letzeren der Doppelpunkt vorangestellt werden.

Der Inhalt einer Tabellenvariable darf entweder mit DML-Anweisungen bearbeitet werden oder mit den anderen vorgestellten Anweisungen, wie zum Beispiel durch Zuweisung, indexbasierten Zugriff oder die Tabellenoperatoren verändert werden. Beide Varianten sind mit der gleichen Tabellenvariable nicht möglich. Tabellenvariablen, die mit DML-Anweisungen verändert werden, nennen wir im Folgenden DML-Tabellenvariablen.

Deklaration von DML Tabellenvariablen

Das bedeutet auch, dass die Definition einer DML-Tabellenvariable nicht implizit über eine Zuweisung erfolgen darf. Stattdessen muss die DML-Tabellenvariable am Anfang eines Blocks mit DECLARE angelegt werden. Die Spaltendefinition erfolgt hier wie bei Datenbanktabellen, das bedeutet, dass Spalten auch als PRIMARY KEY markiert werden und es kann die Einschränkung NOT NULL für einzelne Spalten festgelegt werden. Folgend sehen Sie ein Beispiel für die Deklaration:

DECLARE lt_dml TABLE (vorname  NVARCHAR(30),
nachname NVARCHAR(30));

Um Daten in eine DML-Tabellenvariable einzufügen, müssen wir die INSERT-Anweisung verwenden:

INSERT INTO :lt_dml (SELECT vorname,
nachname
FROM benutzer);

Der lesende Zugriff auf DML-Tabellenvariablen mit einer SELECT-Abfrage funktioniert aber wie bei gewöhnlichen Tabellenvariablen:

SELECT *
FROM :lt_dml;

Falls die gleichen Daten sowohl in DML-Tabellenvariablen mit DML-Anweisungen, als auch in normalen Tabellenvariablen mit den anderen Anweisungen verarbeitet werden sollen, müssen Sie diese von einer Variablen in die andere kopieren:

lt_normal = SELECT * FROM :lt_dml;

Quelle: SQLScript für SAP HANA, 2. Auflage

Fazit

Die neuen DML Tabellenvariablen sind super praktisch. Aber die Inkompatibilität zu den anderen Tabellenvariablen nervt. Vor allem die Inline Deklaration durch eine einfache Zuweisung vermisse ich bei dem neuen Konzept sehr. 

Jetzt Kosten sparen bei der Fortbildung

Für SAP-Beratungshäuser und selbständige SAP-Berater bietet die aktuelle Krise eine gute Gelegenheit, das Know-How auf Vordermann zu bringen. Und das zu wesentlich geringeren Kosten als sonst. 

Vor COVID-19

In den letzten Jahren sind dank der SAP HANA Datenbank und den damit verbundenen, neuen Produkten S/4HANA und BW/4HANA viele Projekte bei SAP-Kunden entstanden. Das hat zu zwei Auswirkungen geführt:

1.      Die Beratungshäuser und selbständigen Berater in dem Bereich sind in letzter Zeit sehr gut ausgelastet gewesen.  

2.      Da die Produkte und Technologien neu sind, fehlen wirklich erfahrene Berater. Es besteht erheblicher Schulungsbedarf.

Und in der Krise…

Viele SAP-Kunden sind momentan sehr vorsichtig mit dem Geld ausgeben. Manche Projekte werden vorübergehend gestoppt, andere werden gar nicht erst begonnen. Und fast überall werden die Budgets für externe Unterstützung reduziert oder gestrichen. Gerade bei Konzernen, deren Mitarbeiter teilweise in Kurzarbeit geschickt werden, ist das gut nachvollziehbar.

Das führt zu schlechter Auslastung der SAP-Beratungshäuser und selbständigen SAP-Experten. Diese können nicht mehr Vollzeit fakturieren. Nach den letzten Jahren mit einer sehr guten Auslastung wird das sicherlich eine Weile lang zu verkraften sein.

…führt der Kostendruck zu Fehlentscheidungen

Um das Jahresergebnis nicht zu belasten, werden natürlich auch dort die Budgets für externe Ausgaben deutlich reduziert. Aber gerade im Bereich der Fortbildung ist das eine betriebswirtschaftliche Fehlentscheidung. Denn es wird außer Acht gelassen, dass die Opportunitätskosten, also die nicht fakturierten Zeiten der Schulungsteilnehmer, den mit Abstand größten Kostenblock bei einer Schulung ausmachen. Diese Kosten entstehen aber nur dann, wenn die Mitarbeiter nahezu voll ausgelastet sind. Und das wird ja hoffentlich bald wieder der Fall sein. Hier ein kleiner Vergleich, bei dem ich die Opportunitätskosten noch recht niedrig angesetzt habe:

Fazit

Schulungsbedarf besteht im Bereich SAP HANA Technologien. Aber wer jetzt schult, kann später, wenn die Auslastung wieder Richtung 100% geht, motivierte und qualifizierte Mitarbeiter voll fakturieren lassen. Wer jetzt aber spart, der wird früher oder später eine wesentlich höhere Rechnung zahlen müssen. 

SAP Schulungen – für das Homeoffice optimiert

In den letzen Wochen habe ich einige Online Schulungen durchgeführt. Dabei habe ich unterschiedliche Tools und Formate ausprobiert. Denn ich möchte nicht einfach nur die bewährten Inhouse Schulungen 1:1 online halten. Und ich habe natürlich auch immer fleißig Feedback von den Teilnehmern eingesammelt, damit mein Angebot optimieren kann.

Zeitlich flexibler

Ein großer Vorteil bei Online Veranstaltungen ist, dass man nicht mehr an feste Zeitblöcke gebunden ist. Die meisten Präsenzschulungen finden tagesweise statt. Meist sind es auch mehrere Tage am Stück. Das ist nicht Ideal, weil es sehr anstrengend ist, einen vollen Tag in einer Schulung zu sitzen. Ich habe es bei Präsenzschulungen gelegentlich erlebt, das einzelnen Teilnehmer nach der Mittagspause die Augen kurz zufallen. Das ist normal – denn wir können uns einfach nicht so lange am Stück konzentrieren.
Bei Online Schulungen sind wir weniger an die Tagesblöcke gebunden. Es ist auch möglich, eine Schulung statt an 3 Tagen á 7 Schulungsstunden auch an 5 Vor- oder Nachmittagen durchzuführen. Und diese Termine kann man auch auf 2 Wochen verteilen. Das hat mehrere Vorteile:

  • Die Schulungsinhalte verteilen sich auf einen längeren Zeitraum. Man bleibt aufnahmefähig und kann auch zwischendurch über die Inhalte nachdenken
  • Das Tagesgeschäft kann weiter gehen. Es ist nicht nötig, dass während der Schulung noch mal eben etwas erledigt wird. Das kann man in der anderen Tageshälfte machen
  • Es ist leichter, Termine zu finden
  • In der schulungsfreien Zeit können die Teilnehmer auch noch mal die Themen anschauen oder Übungen machen
  • Der häufig etwas monotone Homeoffice Alltag wird aufgelockert

Das Vorgehen hat sich bereits in 2 Veranstaltungen bewährt und das Feedback der Teilnehmer war sehr positiv.

Nachvollziehbarer mit Lernportal

Für alle Veranstaltungen erstelle ich in einem Moodle Lernportal einen Kurs. Dieser ist in die einzelnen Lektionen unterteilt und dort finden sich alle notwendigen Informationen:
  • Folien der Lektion
  • Übungsaufgaben
  • Zugangsdaten zu den Schulungssystemen
  • Eine Liste mit offenen Fragen bzw. Themen, die auch von den Teilnehmern gepflegt werden kann
  • Zugangscodes zu den E-Books
  • Anleitungen und How-To Dokumente
  • Aufzeichnungen der Veranstaltung
Das Lernportal ist auch nach der Veranstaltung für die Teilnehmer noch 3 Monate lang zugänglich.
 

Aufgezeichnet!

Alle Veranstaltungen können per Video aufgezeichnet werden. Voraussetzung ist natürlich, dass alle Teilnehmer damit einverstanden sind. Hinterher werden diese Aufzeichnungen dann geschnitten in Abschnitte von maximal 1-2 Stunden und bei den entsprechenden Lektionen im Lernportal hinterlegt. Damit ist es dann möglich, die Schulung Schritt für Schritt nachträglich noch mal nachzuvollziehen und bei Bedarf können einzelne Lektionen noch mal angesehen werden.

Bei den Feedbackumfragen geben über 80% der Teilnehmer an, dass sie vorhaben, später noch mal das Lernportal zu nutzen bzw. die Aufzeichnungen noch mal anzusehen.

E-Books und Hardcover

Alle Teilnehmer bekommen wie gehabt ein persönliches Exemplar von „SQLScript für SAP HANA (oder ein anderes, zum Thema passendes Buch) als Schulungsunterlage. Da fast jeder Teilnehmer im Homeoffice arbeitet, ist das auch eine logistische Herausforderung. Da hat es sich als praktisch erwiesen, wenn man zusätzlich noch die E-Book Version des Schulungsmaterials dazu nimmt. Damit ist trotz langer Postlaufzeiten gewährleistet, dass alle Teilnehmer das Buch pünktlich haben. Und es hat natürlich auch einen großen Mehrwert, weil man es überall mit dabei haben kann und man kann natürlich auch gut darin suchen. 
 

Mit Garantie und Support

Ich bin davon überzeugt, dass meine Kunden mit dem Online Angebot zufrieden sind. Wenn das nicht der Fall ist, können alle Teilnehmer kostenlos an einer der hoffentlich bald wieder stattfindenden Präsenzschulungen hier in Mannheim teilnehmen. Versprochen!

Und weil einem manchmal die wichtigen Fragen erst nach der Schulung einfallen, können alle Teilnehmer nach einer Schulung kostenlosen Support zu allen Fragen rund um das Schulungsthema in Anspruch nehmen. Melden Sie sich einfach über unser Support Portal und wir werden uns um Ihre Fragen kümmern. 

Fazit

Natürlich fehlt mir bei Online Schulungen immer ein bisschen der informelle, persönliche Kontakt zu den Teilnehmern, sei es beim Mittagessen oder in der Kaffeepause. Aber wenn man die Möglichkeiten des Internets nutzt, kann man Online Schulungen veranstalten, die genau so wertvoll und nützlich für die Teilnehmer sind wie Präsenzveranstaltungen. 

Die 2. Auflage von „SQLScript für SAP HANA“

Am 25. Mai 2020 erschien die 2., aktualisierte und erweiterte Auflage  der deutschen Ausgabe meines Buches SQLScript für SAP HANA im Rheinwerkverlag. Ich hätte beim Erscheinen der ersten Auflage im September 2018 nie gedacht, dass die Nachfrage so groß sein wird, dass eine 2. Auflage notwendig sein wird.

Ebenfalls nicht erwartet hatte ich, dass sich mein Geschäft von der reinen Beratung und Entwicklung immer mehr in Richtung Training und Coaching verschiebt. Aber die Nachfrage nach qualitativen Schulungen im Bereich SQLScript und SAP HANA Technologien ist nach wie vor groß. Und das positive Feedback meiner Teilnehmer hat mich dazu ermutigt, jetzt überwiegend Schulungen zu machen. Vielen Dank für die vielen positiven Rückmeldungen!

Und so kam es, dass ich selber mit der größte Abnehmer meiner eigenen Bücher wurde. Mittlerweile müssten das fast 250 Exemplare gewesen sein, die ich an meine Schulungsteilnehmer übergeben habe.

Was ist neu in der 2. Auflage

Seit Ende letztem Jahres habe ich an den Ergänzungen und Aktualisierungen für die 2. Auflage von SQLScript für SAP HANA geschrieben. In den letzten zwei Servicepacks sind viele spannende Features zur Sprache SQLScript hinzugekommen, von denen ich einige unbedingt in die neue Auflage einbringen wollte.

Für ein paar davon habe ich auch schon Blog-Artikel geschrieben:

Die anderen Themen seien hier nur kurz aufgelistet. So wie ich ausreichend Zeit dafür finde, werde ich auch für diese etwas mehr schreiben:

  • Lateral Join – Die Bezeichnung Lateral Join ist etwas irreführend, da es sich nicht um eine weitere Join-Art handelt, wie z. B. Inner Join oder Left Outer Join. Vielmehr handelt es sich beim Lateral Join um einen Join, bei dem der Join-Partner eine korrelierte Unterabfrage oder eine Funktion ist. Sie können sich einen Lateral Join so vorstellen, dass die Unterabfrage für jede Zeile des bisherigen Ergebnisses separat ausgeführt wird. Es ist möglich, auf die Daten der aktuellen Zeile über den Korrelationsnamen zuzugreifen.
  • Die Bibliothek SQLSCRIPT_STRING bietet zusätzliche Funktionen, um Zeichenketten zu Verarbeiten:
    • Mit SPLIT kann man eine Zeichenkette an Trennzeichen in mehrere kleine Abschnitte zerlegen
    • Mit FORMAT kann man eine Zeichenkette mit einer Syntax aus der Sprache Python formatieren
    • Und mit TABLE_SUMMARY kann man aus einer Tabelle eine Zeichenkette machen
  • Mit der ABAP BASIS 7.53 sind skalare AMDP Funktionen möglich. Das ist gerade für die BW/4HANA Routinenentwicklung sehr wichtig, da diese bislang nicht möglich waren.
  • Mit den Funktionen SERIES_GENERATE_ können Datenreihen erzeugt werden. Das ist insbesondere für Datumswerte sehr praktisch.

Und natürlich sind noch unzählige kleinere Ergänzungen und Korrekturen enthalten. Beispielsweise wurden viele Screenshots der BW Oberflächen in der SAP GUI durch die neuen BW/4HANA Oberflächen in Eclipse ersetzt.

Insgesamt ist der Gesamtumfang der 2. Auflage von SQLScript für SAP HANA um 38 Seiten gewachsen. Der Aufwand für das Buchprojekt ist mal wieder viel höher gewesen als ursprünglich geplant. Aber das Ergebnis kann sich sehen lassen.