Open Source im professionellen Einsatz
Linux-Magazin 12/2015
© sergwsq, 123RF

© sergwsq, 123RF

Überraschung in SQL: Moderne Möglichkeiten der Abfragesprache

Jugendsprache

SQL schafft es derzeit nur noch als Antithese in die Medien: NoSQL ist das Hype-Thema. Tatsächlich aber hat die klassische Datenbanksprache viel mehr zu bieten, als den meisten klar ist. Seit SQL:92 kamen mit jeder Version verblüffende neue Funktionen dazu.

1261

Modernes SQL hat mehr drauf, als viele denken. Zum Beispiel ist kaum bekannt, dass SQL längst nicht mehr auf das relationale Datenmodell beschränkt ist, sondern auch mit verschachtelten Objekten und strukturierten Dokumenten umgehen kann. Dafür braucht man kein NoSQL. Dieser Artikel unternimmt einen Streifzug durch die jüngere SQL-Geschichte und zeigt, was die Sprache heute alles leisten kann.

Ausgangspunkt ist der Standard SQL:92, der allgemein bekannt sein dürfte, handelt es sich dabei doch um das klassische, relationale SQL. SQL:92 war bereits die zweite große Version des SQL-Standards, hatte dementsprechend eine gewisse Vollständigkeit erreicht und ist noch heute eine runde Sache – für Anwender, die sich mit dem relationalen Modell begnügen. Dass das relationale Modell nicht für alle Daten ideal ist, war aber schon 1992 bekannt.

Der Urknall – SQL:1999

So kam es 1999 zur dritten großen Version des Standards und damit zum Ende des rein relationalen SQL. Alle Kompasse zeigten damals in Richtung objektorientierter Programmierung. Diesem Trend folgte der Standard mit der objektrelationalen Datenbank. Leider kam er damit aber einige Jahre zu spät. In der Zwischenzeit keimten nämlich objektrelationale Mapper (ORM) auf, die eine Brücke zwischen der objektorientierten Programmierung und dem relationalen Datenmodell bilden sollten.

Neben dem Hauptthema objektrelationale Datenbank bot SQL:1999 auch andere Neuerungen, die sich später besser durchsetzten. Einen dieser Themenbereiche, den der Standard auf breiter Basis unterstützte, beschreibt dieser Beitrag genauer: Schleifen.

Auch wenn SQL:1999 mit mancher Tradition gebrochen hat, so blieb es doch eine deklarative Sprache. Das heißt, dass es per Definition nicht möglich ist, der Datenbank vorzuschreiben, wie sie eine Abfrage auszuführen hat. Solange das Ergebnis stimmt, hat die Datenbank alle Freiheiten. Insofern kann es hier auch keine Schleifen geben, denn die definieren ja gerade die Art und Weise der Lösung. Der Kunstgriff, den SQL an dieser Stelle macht, besteht darin, Konstrukte zu schaffen, die nur als Schleifen ausführbar sind. Diese Konstrukte kann man dann de facto wie Schleifen verwenden, die es in einer deklarativen Sprache eigentlich nicht geben darf.

Als Beispiel soll der PHP- und SQL-Code aus Listing 1 in reines SQL übersetzt werden. Dieses Beispiel lädt zuerst eine Liste von Kategorien in ein PHP-Array und führt dann für jede Kategorie eine weitere Abfrage aus, die die drei jeweils populärsten Produkte jeder Kategorie liefert.

Listing 1

PHP-SQL-Pseudocode

01 $produkt_kategorien = array(SELECT kategorie FROM produkt_kategorien);
02 foreach ($produkt_kategorien as $kategorie) {
03  SELECT *
04  FROM produkte
05  WHERE kategorie = $kategorie
06  ORDER BY popularitaet
07  LIMIT 3;
08 }

Performance-bewusste Anwender könnten an dieser Stelle einwenden, dass es oft zu Problemen führt, wenn man Datenbankabfragen in Schleifen einer imperativen Sprache – hier PHP – platziert. Ein Join ist in der Regel zu bevorzugen, damit die Datenbank alle benötigten Daten auf einmal liefert. In diesem Fall entsteht aber ein Problem: Das Beispiel lässt sich nicht mit einem einfachen Join lösen. Die Beispiele aus Listing 2 zeigen: Egal wie man es dreht und wendet, das Ergebnis sind immer die drei insgesamt populärsten Produkte – nicht die drei populärsten pro Kategorie.

Listing 2

Zwei Versuche mit Joins

01 SELECT *
02  FROM produkt_kategorien k
03  JOIN produkte p ON (p.kategorie = k.kategorie)
04  ORDER BY popularitaet
05  LIMIT 3
06
07 SELECT *
08  FROM produkte
09  WHERE kategorie IN (SELECT kategorie FROM produkt_kategorien)
10  ORDER BY popularitaet
11  LIMIT 3

Das Problem ist, dass »LIMIT« nicht pro Kategorie wirkt. Um das gewünschte Ergebnis zu erhalten, müsste man »LIMIT« in einer Unterabfrage anwenden, die auf eine Kategorie eingeschränkt ist (Listing 3). Dies ist jedoch kein gültiges SQL mehr, da Unterabfragen in der »FROM« -Klausel nicht auf Daten außerhalb dieser Unterabfrage zugreifen können.

Listing 3

Mit Unterabfrage

01 SELECT *
02  FROM produkt_kategorien k
03  CROSS JOIN (SELECT *
04  FROM produkte p
05  WHERE p.kategorie = k.kategorie
06  ORDER BY popularitaet
07  LIMIT 3
08  ) top_produkte

Die »WHERE« -Klausel, die mit »k.kategorie« auf eine Tabelle außerhalb der Unterabfrage zugreift, ist also ungültig. Zumindest ist das in SQL:92 so. SQL:1999 erlaubt solche Zugriffe dennoch, wenn der Anwender der Unterabfrage das neue Schlüsselwort »LATERAL« voranstellt (siehe Listing 4).

Listing 4

LATERAL

01 SELECT *
02  FROM produkt_kategorien k
03  CROSS JOIN LATERAL (SELECT *
04  FROM produkte p
05  WHERE p.kategorie = k.kategorie
06  ORDER BY popularitaet
07  LIMIT 3
08  ) top_produkte

Diese Abfrage entspricht also dem PHP-Code von oben, nur dass die Datenbank selbst die Schleife ausführt und damit die Latenzzeiten zwischen Applikation und Datenbank wegfallen. Abbildung  1 stellt die Analogie zwischen Foreach-Schleife und »LATERAL« nochmals dar.

Abbildung 1: PHP-Pseudocode und SQL-LATERAL-Schleifen im Vergleich.

Ein weiterer Vorteil, alles in SQL zu erledigen, besteht darin, dass der Anwender das Ergebnis mit SQL weiterbearbeiten kann. So kann er das Gesamtergebnis zum Beispiel mit einer »ORDER BY« -Klausel anders sortieren oder mit »INSERT INTO **... **SELECT **...« direkt in eine Caching-Tabelle schreiben. Der letztere Fall vermeidet den Transport der Daten von der Datenbank in die Applikation und zurück komplett.

Der Vorteil, Ergebnisse mit SQL weiterbearbeiten zu können, gilt natürlich für jede SQL-Abfrage. Generell sollten Nutzer von der Vorstellung abkommen, dass SQL-Datenbanken nur Speicher sind. Oft ist die Datenaufbereitung mit SQL einfacher als mit anderen Programmiersprachen. Das Ergebnis ist in der Regel sogar korrekter und performanter. Dieser Ansatz versagt erst bei massiv parallelen Zugriffen, wie sie bei Google, Facebook & Co. vorkommen. Wer so groß ist, hat aber auch entsprechende Mittel, proprietäre Lösungen zu bauen. Bis dahin ist die Flexibilität von SQL in den meisten Fällen der bessere Weg.

SQL:1999 hat noch ein zweites Konstrukt eingeführt, das ebenfalls wie eine Schleife zu benutzen ist: »WITH RECURSIVE« . Wie es im Detail funktioniert, ist recht komplex und führt hier zu weit, das Grundprinzip verdeutlicht aber die Abbildung  2.

Abbildung 2: with recursive-Schleifen in SQL.

Die Variante »WITH RECURSIVE« hat drei Vorteile:

  • Es wird von aktuellen Datenbanken besser unterstützt als »LATERAL« – zum Beispiel auch von SQlite (siehe Abbildung  3).
  • Es lassen sich Daten von einer Iteration an die nächste weiterreichen.
  • Es ist möglich, eine dynamische Abbruchbedingung zu formulieren.

Der Nachteil ist, dass der Schleifenkörper (Body) nicht eins zu eins in SQL zu übertragen ist: Er muss mit dem Teil nach »union **all« verschmelzen.

Dennoch gibt es wichtige Anwendungsfälle. Die in Abbildung  2 gezeigte Abfrage ist ein so genannter Zeilengenerator, sie liefert einfach zehn nummerierte Zeilen – besonders praktisch zum Erzeugen von Testdaten. Der wichtigere Anwendungsfall ist jedoch das Durchwandern von Graphen, wie es zum Beispiel vorkommt beim Suchen der kürzesten Verbindung zwischen zwei Personen in einem sozialen Netzwerk.

In schnellen Schritten – SQL:2003

Nachdem das rein relationale Denken mit SQL:1999 überwunden war, dauerte es nur vier Jahre bis zur nächsten großen Überarbeitung des Standards. Der Fokus lag dabei auf zwei Punkten: XML und analytischen Funktionen.

Die XML-Unterstützung ist insofern interessant, da SQL-Datenbanken damit – wie man heute sagen würde – zu vollwertigen Document Stores wurden. Mit SQL:2003 kann der Anwender XML nicht mehr nur als Text abspeichern, sondern als validiertes Dokument, das sich mit SQL und XQuery bearbeiten lässt.

Obwohl mittlerweile einige Datenbanken die XML-Erweiterung unterstützen, konnte sich XML in der Webentwicklung jedoch nicht durchsetzen. Der Konkurrent Json war einfach zu verführerisch. Und so kommt es, dass in den letzten Jahren de facto alle gängigen SQL-Datenbanken ähnliche Funktionen für den Umgang mit Json-Dokumenten eingeführt haben. Das sind jedoch proprietäre Erweiterungen – jede Datenbank bietet andere Funktionen an.

Doch der zweite SQL:2003-Schwerpunkt – analytische Funktionen – hat sich durchgesetzt. Insbesondere die so genannten Window-Funktionen unterstützen heute viele Datenbanken. Sie vereinfachen die Datenaufbereitung wesentlich.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 6 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • PostgreSQL 9.5

    Wie erwartet gibt es auch in diesem Herbst eine neue Release des Open-Source-Datenbanksystems PostgreSQL. Sie bietet eine ganze Reihe überzeugender neuer Features.

  • Renntrimm

    Geschickte Konfiguration und Geschwindigkeits-optimierte SQL-Selects verbessern die Performance einer Datenbankanwendung ganz ohne zusätzliche teure Hardware merklich - demonstriert am Beispiel von Oracle-Datenbanken unter Linux.

  • Daten am Mann

    Die Datenbank läuft auf dem Server - dieses bisher gültige Dogma durchbricht die Javascript-Datenbank-Engine Public SQL. Für die rein Client-seitige Webseitenprogrammierung eröffnen sich damit interessante Möglichkeiten: Daten lassen sich ohne Nachladen visualisieren.

  • Schneller orakeln

    Mit Oracle 8i hat die Datenbankfirma einen wichtigen Schritt getan, um ihr Flaggschiff Internet-ready zu machen. Doch sobald eine Oracle-Datenbank in den Einsatz für Internet-Dienste geht, zeigt es sich, ob auch Entwickler und Administratoren ihr Handwerk gut genug verstehen, um ausreichende Geschwindigkeit auf Dauer zu gewährleisten.

  • Probeabstimmung

    Two-Phase-Commits öffnen die Tür für verteilte Datenbanken: Nur nach einstimmiger Abstimmung geben sie Transaktionen ihr Okay. Der Bitmap-Scan beschleunigt Anfragen nach Werten aus mehreren Spalten. Das sind nur zwei Beispiele für viele Verbesserungen in der neuen PostgreSQL-Version 8.1.

comments powered by Disqus

Ausgabe 11/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.