Literarisches SQL


Literate programming ist eine von Donald Knuth propagierte Programmiermethode, die – unter anderem – danach strebt, den Quelltext so zu gestalten, dass er wie ein Roman von vorne nach hinten gelesen werden kann.

SQL funktioniert genau umgekehrt: Die Verschachtelung von Unterabfragen führt dazu, dass man zuerst die innerste Abfrage suchen und verstehen muss, um sich von dort aus nach außen arbeiten zu können. Nicht einmal gut gewählte Namen können diesen rekursiven Leseprozess merklich verbessern, weil die Namen den Unterabfragen folgen.

Sogar die Reihenfolge der Klauseln der einfachsten SQL-Abfrage hat eine Vorwärtsabhängikeit: Die Bedeutung der select-Klausel hängt von der from-Klausel ab. Das stellt Entwicklungswerkzeuge sogar vor eine unlösbare Aufgabe: Wenn man select eingibt, ist noch nicht bekannt, auf welche Tabellen zugegriffen wird und daher auch nicht, welche Spalten sichtbar sind. Ohne from-Klausel keine sinnvollen Vorschläge für die select-Klausel.

Mit SQL:1999 wurde zumindest zur Verschachtelung eine Alternative geschaffen: die with-Klausel. Im Zusammenhang mit literarischem SQL hat die with-Klausel zwei wichtige Eigenschaften: (1) Namen kommen zuerst; (2) Unterabfragen können beliebig angeordnet werden.

Namen zuerst

Die Wichtigkeit aussagekräftiger Namen für Softwarekomponenten kann nicht genug betont werden. Aber selbst der beste Name, der die Absicht der Komponente verrät, ist nutzlos, wenn er im entscheidenden Moment nicht ins Auge springt:

SELECT ...
  FROM (SELECT ...
          FROM ...
       ) intention_revealing_name
   ...

Je länger die innere Abfrage wird, desto wichtiger ist ein guter Name, aber desto weiter wird er auch aus dem Blickfeld geschoben. Wie tragisch.

Bei der with-Klausel steht der Name jedoch vor dem Code, so wie bei Funktionsdeklarationen in praktisch jeder anderen Programmiersprache:

WITH intention_revealing_name AS (
     SELECT ...
       FROM ...
     )
SELECT ...
  FROM intention_revealing_name irn
   ...

Als kleines Extra kann man in der from-Klausel noch immer einen kurzen Alias vergeben (irn im Beispiel).

Reihenfolge der menschlichen Logik

Der zweite Aspekt der with-Klausel ist, dass man damit Verschachtelungen in Verkettungen verwandeln kann. Dadurch werden komplexe Abfragen von oben nach unten lesbar.

Eine with-Klausel kann mehrere Abfragen beinhalten. Jede davon kann sich bereits auf zuvor definiert Abfragen aus derselben with-Klausel beziehen. Das ist genau, was man für literarisches SQL braucht.

Das folgende Beispiel skizziert eine literarische Abfrage. Die ersten beiden Definitionen werden nicht einmal gezeigt – die Namen alleine verraten den Zweck:

WITH frequently_bought_together (ordered, suggested, times) AS (
     SELECT ...
     )
   , frequently_bought_shortly_after (ordered, suggested, times) AS (
     SELECT ...
     )
   , product_recommendation (ordered, suggested, times) AS (
     SELECT ordered, suggested, SUM(times)
       FROM (SELECT * FROM frequently_bought_together
              UNION ALL
             SELECT * FROM frequently_bought_shortly_after
            ) frequently_needed_together
      GROUP BY ordered, suggested
      ORDER BY SUM(times) DESC
      FETCH FIRST 1 ROW ONLY 
     )
SELECT *
  FROM product_recommendation

Die Leichtigkeit des Lesens ergibt sich nicht automatisch aus der Von-oben-nach-unten-Struktur. Mit sinnlosen Namen wie x, y, und z wäre die Abfrage noch immer schwer zu verstehen. Erst das Zusammenspiel aus guten Namen und guter Struktur bringt den literarischen Durchbruch.

Wie so oft kann man es natürlich auch mit der Aufteilung in with-Abfragen übertreiben. Kleine Unterabfragen wie frequenlty_needed_together im Beispiel müssen die Leserbarkeit nicht unbedingt stören. Wichtig ist eine Aufteilung in überschaubare, logisch zusammengehörende Einheiten.

Andererseits macht es manchmal Sinn, in einer with-Abfrage selbst wiederum eine with-Klausel zu verwenden. Man ist nicht auf eine globale Spaghetti-with-Klausel beschränkt: Syntaktisch gesehen ist with ein Präfix für select. Nutze es dort, wo es die Lesbarkeit am besten unterstützt.

Spätestes jetzt sollte es klar sein, warum diese Technik „literarisches SQL“ heißt: Lesbare Abfragen zu schreiben ist eine Kunst, keine Wissenschaft.

Performanceaspekte

Bei manchen Datenbanken – insbesondere PostgreSQL – kann die Verwendung der with-Klausel die Performance beeinflussen. Siehe ”Performanceaspekte“.

Kompatibilität

Über den Autor

Foto von Markus Winand

Markus Winand lehrt effizientes SQL – inhouse und online. Er minimiert die Entwicklungszeit durch modernes SQL und optimiert die Laufzeit durch schlaue Indizierung – dazu hat er auch das Buch SQL Performance Explained veröffentlicht.

„modern SQL“ von Markus Winand ist unter einer Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License lizenziert.
Impressum | Kontakt | KEINE GEWÄHR | Handelsmarken | Datenschutz | CC-BY-NC-ND 3.0 Lizenz