Ein gigantischer Sprung für SQL: MySQL 8.0 veröffentlicht


„Verwendest Du noch immer SQL-92“ ist die Eröffnungsfrage meines Modern-SQL-Vortrages. Ein erstaunlich großer Teil des Publikums gesteht dann ganz offen, eine 25 Jahre alte Technologie zu verwenden. Bei der Frage, wer noch Windows 3.1 einsetzt – ebenfalls 1992 erschienen – heben nur ein paar Spaßvögel die Hand.

Natürlich ist dieser Vergleich nicht ganz fair. Dennoch zeigt sich dabei, dass es um das Wissen über neuere SQL-Standards schlecht bestellt ist. Seit SQL-92 gab es nämlich fünf Aktualisierungen. Die derzeitig gültige Fassung ist SQL:2016. Viele Entwickler haben noch nie davon gehört.

Viele Entwickler wissen also nicht, dass SQL seit 1999 nicht mehr auf die relationale Algebra oder das relationale Modell beschränkt ist. SQL:1999 hat nämlich Operationen eingeführt, die keine Entsprechung in der relationalen Algebra haben (with recursive, lateral) und Datentypen in den Standard aufgenommen, die die klassische Vorstellung der ersten Normalform brechen (array)0.

Seit damals – also seit 19 Jahren – ist es nicht mehr wichtig, ob eine SQL-Funktion der relationalen Idee entspricht. Wichtig ist, das eine Funktion eine wohldefinierte Semantik hat und ein echtes Problem löst. Der akademische Ansatz ist einem Pragmatischem gewichen. Heute bietet SQL für fast alle Datenverarbeitungsprobleme eine praktische Lösung an. Manche entsprechen dem relationalen Gedanken, andere nicht.

Vorsatz

Zu SQL-Datenbanken nicht relationale Datenbank sagen. SQL ist wirklich mehr als nur relational.

Schade nur, dass viele Entwickler SQL noch immer wie vor 25 Jahren benutzen. Ich glaube, das liegt hauptsächlich am mangelnden Know-how und Interesse der Entwickler1 und an der schwachen Unterstützung in den Datenbankprodukten.

Lass uns dieses Argument mit Blick auf MySQL betrachten. Wenn ich mir den Marktanteil ansehe, glaube ich, dass MySQL’s Mangel an modernem SQL mehr als nur seinen gerechten Teil zu dieser traurigen Situation beigetragen hat. Dieses Problem habe ich 2013 in meinem Artikel „MySQL is as bad for SQL as MongoDB is to NoSQL“ anklingen lassen. Die Schlüsselaussage ist dass „MongoDB ein populärer, aber schlechter Vertreter seiner Art ist – genau wie MySQL für SQL“. Joe Celko hat seine Meinung über MySQL anders ausgedrückt: „MySQL ist nicht SQL, es leiht sich lediglich die Schlüsselworte von SQL aus“.

Beispiele für die fragwürdige Auslegung von SQL gibt es im MySQL WAT-Vortrag auf YouTube [Englisch].2 Beachte, dass dieses Video von 2012 ist und sich auf MySQL 5.5 bezieht (die aktuelle Version zu dieser Zeit). Seit damals hat sich die Situation durch die Versionen 5.6 und 5.7 deutlich gebessert.3

Besonders erfreulich ist, dass bei der Einführung der neuen Standardwerte einen Schritt weiter gedacht wurde, um die Auswirkungen geänderter Standardeinstellungen möglichst gering zu halten. Als zum Beispiel ONLY_FULL_GROUP_BY standardmäßig aktiviert wurde, hat man sich die Mühe gemacht, die vielleicht vollständigste Prüfung funktionaler Abhängigkeiten mitzuliefern.

BigQueryDb2 (LUW)MariaDBMySQLOracle DBPostgreSQLaSQL ServerSQLiteBasistabelle: PRIMARY KEYBasistabelle: UNIQUEJoined TableWHERE-KlauselGROUP BY-Klausel
  1. Nicht bei Joins auf Primärschlüssel oder Unique-Constraints

Es war ungefähr zu dieser Zeit – als MySQL 5.7 herauskam – das ich aufhörte, MySQL zu verspotten. Ich mache natürlich nur Spaß. Natürlich mache ich mich gelegentlich noch über MySQL lustig. Es ist aber schon etwas schwieriger geworden.

Apropos, wusstest du, dass MySQL noch immer keine Check-Constraints unterstützt? Wie in früheren Versionen kann man bei create table zwar check-Klauseln angeben, sie werden aber stillschweigend ignoriert. Ja, stillschweigend: keine Fehlermeldung, keine Warnung. Das hat sogar MariaDB bereits vor einem Jahr behoben. (Update April 2019: MySQL 8.0.16 prüft nun check-Constraints).

BigQueryDb2 (LUW)MariaDBMySQLOracle DBPostgreSQLSQL ServerSQLiteCheck-Constraints

Ach, jetzt mach ich mich schon wieder über MySQL lustig. Entschuldigung, alte Gewohnheit!

Ungeachtet dessen hat sich die Entwicklungsphilosophie von MySQL mit den letzten Versionen spürbar geändert. Was ist geschehen? Du weißt es wohl schon: MySQL steht unter neuer Führung, seit Oracle es mit Sun mitgekauft hat. Und ich muss gestehen: Das war vielleicht das Beste, das SQL den letzten 10 Jahren passiert ist. Und damit meine ich wirklich SQL – nicht MySQL!

Der Grund, warum ich glaube, dass eine einzelne MySQL-Version einen dramatischen Effekt auf das ganze SQL-Ökosystem hat, ist einfach: MySQL ist das schwächste Glied der Kette. Wenn man dieses Glied stärkt, stärkt man die ganze Kette. Lass mich das ausführen.

MySQL ist sehr populär. Laut db-engines.com die zweitbeliebteste SQL-Datenbank überhaupt. Wichtiger noch: die mit großem Abstand beliebteste Gratis-SQL-Datenbank. Diese Popularität hat Auswirkungen auf alle, die sich mit mehr als bloß einer bestimmten SQL-Datenbank befassen. Das sind oft unabhängige Softwarehersteller, die zum Beispiel Redaktionssysteme (CRM), Webshops oder Object/Relationale-Mapper (ORMs) herstellen. Aufgrund der immensen Popularität ist es für diese Hersteller oft notwendig, MySQL zu unterstützten. Nur wenige davon nehmen es auf sich, mehrere Dialekte ordentlich zu unterstützen – Java Object Oriented Querying (jOOQ) sticht hier besonders löblich hervor. Viele Hersteller limitieren sich einfach auf den gemeinsam unterstützten SQL-Dialekt. Also im Wesentlichen auf MySQL.

Eine andere Personengruppe, die von der Omnipräsenz von MySQL betroffen ist, sind Leute, die SQL lernen wollen. Für diese drängt sich MySQL ja gerade zu auf: gratis und beliebt. Das muss doch eine gute Basis zum Lernen sein. Was sie nicht wissen ist, dass sie Ihre SQL-Fähigkeiten damit auf Basis des schwächsten SQL-Dialektes unter den gängigen Datenbanken aufbauen. Frei nach Joe Celko bedeutet das, dass diese Personen die Schlüsselworte zwar kennen, deren Bedeutung aber nicht richtig verstehen. Von modernem SQL haben sie dann natürlich auch noch nichts gehört.

Letzte Woche hat sich das alles geändert als Oracle endlich eine stabile Version (GA) von MySQL 8.0 herausgebracht hat. Diese Version ist ein Meilenstein, da MySQL damit endlich über SQL-92 und das rein relationale Dogma hinauswächst. Neben einiger anderer Standard-SQL-Funktionen unterstützt MySQL jetzt Window-Funktionen (over) und Common-Table-Expressions (CTE, with). Ohne jeden Zweifel die beiden wichtigsten SQL-Funktionen seit SQL-92.

Gezählt sind also die Tage, an denen Hersteller behaupten, sie können diese Funktionen nicht, nutzen weil MySQL sie nicht unterstützt. Window-Funktionen und CTEs sind jetzt in der Dokumentation der beliebtesten gratis SQL-Datenbank. Daher möchte ich kühn behaupten: MySQL 8.0 ist ein kleiner Schritt für eine Datenbank, aber ein gigantischer Sprung für SQL4.

Und es wird noch besser: Die Zukunft ist ebenfalls rosig! Als MySQL in die Fänge von Oracle geriet, hat ein Teil des MySQL-Teams (unter Ihnen der Gründer) eine eigene Version abgespalten: MariaDB. Wie es scheint ist es die Strategie von MariaDB durch die Einführung viele neuer Funktionen MySQL-Nutzer für das eigene Produkt zu begeistern. Meiner Meinung nach kommt die Qualität dabei zu kurz – wie zuvor bei MySQL – aber das ist eine andere Geschichte. An dieser Stelle ist es wichtiger, dass MariaDB bereits vor einem Jahr begonnen hat Check-Constraints zu prüfen. Es stellt sich also die Frage: Wie lange kann es sich MySQL noch leisten, Check-Constraints zu ignorieren? Man könnte auch Fragen, wie lange sie meinen Spott noch ertragen.

Hinweis in eigener Sache

Ich biete SQL Schulungen, Optimierung und Beratung an. Auch der Kauf meines Buches „SQL Performance Explained“ (ab €9,95) unterstützt meine Arbeit an dieser Webseite.

Mit MariaDB 10.2 wurde neben Check-Constraints auch Window-Funktionen und CTEs eingeführt. Zu dieser Zeit hatte MySQL gerade eine Beta-Version mit CTEs, aber noch keine Window-Funktionen. MariaDB bewegt sich also schneller.5

Mit Version 10.3 plant MariaDB „System-Versionierte-Tabellen“ einzuführen. In aller kürze: Nachdem diese Funktion für eine Tabelle aktiviert wurde, behält die Datenbank alte Zeilenversionen, wenn mein ein Update oder Insert ausführt. Bei Abfragen erhält man natürlich die jeweils letztgültigen Daten, außer man verwendet eine spezielle Syntax (as of) um nach alten Versionen zu fragen. Mehr dazu in der Ankündigung von MariaDB.

System-Versionierung wurde mit SQL:2011 in den Standard eingeführt. Aktuell sieht es danach aus, als würde MariaDB die erste gratis SQL-Datenbank werden, die diese Funktion unterstützt. Ich hoffe, das das ein Anreiz für andere Hersteller ist und das die Nachfrage nach modernen SQL-Funktionen damit generell steigt.

Jetzt, wo endlich Bewegung in die Umsetzung von modernem SQL kommt, bleibt nur noch ein Problem: die Details! Die Funktionen des SQL-Standards bestehen häufig aus unzähligen Unterfunktionen. Schon alleine deswegen ist es üblich, nicht alle Aspekte zu unterstützen. Am Beispiel Window-Funktionen bedeutet das, dass es nicht genügt zu sagen, dass eine Datenbank Window-Funktionen unterstützt. Welche Window-Funktionen werden wirklich unterstützt? Welche Rahmeneinheiten (rows, range, groups)? Die Antworten auf diese Fragen unterschieden einen Marketing-Gag von einer mächtigen Funktion.

In meiner Mission Entwicklern modernes SQL besser zugänglich zu machen, teste ich diese Details um die Unterschiede hervorzuheben. Die Ergebnisse sind in Matrizen wie oben dargestellt. Im restlichen Artikel soll es daher darum gehen, die neuen Standard-SQL-Funktionen von MySQL 8.0 mit den Mitbewerbern zu vergleichen. Wie du sehen wirst, wurde mit MySQL 8.0 grundsätzlich gute Arbeit geleistet. Nur die neuen JSON-Funktionen stellen eine Ausnahme dar.

Window-Funktionen

Es gab SQL vor Window-Funktionen und es gibt SQL nach Window-Funktionen. Window-Funktionen sind ohne Übertreibung ein „Game Changer“. Wenn man sie einmal verstanden hat, weiß man nicht mehr, wie man jemals ohne leben konnte. Häufige Anwendungsfälle wie die besten N-Zeilen pro Gruppe finden, fortlaufende Summen und gleitender Mittelwerte bilden oder das Zusammenfassen aufeinanderfolgender Ereignisse sind nur die Spitze des Eisberges. Window-Funktion sind das wichtigste Werkzeug zur Vermeidung von Self-Joins. Alleine das macht viele SQL-Abfragen kleiner und schneller. Window-Funktionen sind dermaßen mächtig, dass sogar neue SQL-Implementierungen wie der Apache Foundation (Hive, Impala, Spark), NuoDB oder Google BigQuery sie bereits vor Jahren eingeführt haben. Es ist also durchaus angemessen zu sagen: MySQL erscheint etwas spät zu dieser Party.

Die folgende Matrix zeigt, wie gut gängige SQL-Datenbanken die unterschiedlichen Aspekte der Over-Klausel unterstützen. Wie man sieht, übertrifft MySQL sogar den Funktionsumfang der „weltweit fortschrittlichsten relationalen Open-Source-Datenbank“, wie sich PostgreSQL auf der neuen Homepage selbst beschreibt. PostgreSQL 11 bereitet sich aber darauf vor, die Führungsrolle in diesem Bereich wieder zu übernehmen.

BigQueryaDb2 (LUW)aMariaDBaMySQLOracle DBPostgreSQLccSQL ServerbSQLiteaOVER (<window specification>)OVER <name> und WINDOW-KlauselRahmeneinheit: ROWSRahmeneinheit: RANGERahmeneinheit: GROUPSAbgekürzte Rahmen: <UNIT>…PRECEDINGRahmen: EXCLUDE
  1. Range-Rahmen unterstützen keine Datetime-Datentypen
  2. Range-Rahmen können keine <Distanz> (nur unbounded und current row)
  3. Wird für PostgreSQL 11 erwartet

Die eigentlichen Window-Funktionen, die von MySQL 8.0 angeboten werden, sind auch fast am aktuellen Stand der Mitbewerber.

BigQuerybchkDb2 (LUW)abdiMariaDBabejlMySQLabfjlOracle DBgPostgreSQLabcjlSQL ServeragSQLiteabcjlAggregate (count, sum, min, ...)Distinct in AggregatenROW_NUMBERRANKDENSE_RANKPERCENT_RANKCUME_DISTNTILELEAD und LAGFIRST_VALUE, LAST_VALUENTH_VALUEVerschachtelte Fensterfunktionen
  1. DISTINCT-Aggregate werden nicht unterstützt
  2. Auch ohne ORDER BY-Klausel
  3. Kein respect|ignore nulls
  4. Keine negativen Offset-Werte • Proprietäre Null-Behandlung: lead(<expr>, 'IGNORE NULLS') (ein String-Argument)
  5. Kein Default-Wert möglich (kein drittes Argument) • Kein respect|ignore nulls
  6. Keine negativen Offset-Werte • Kein ignore nulls
  7. Keine negativen Offset-Werte
  8. Proprietäre Null-Behandlung: first_value(<expr> IGNORE NULLS) (kein Komma)
  9. Proprietäre Null-Behandlung: first_value(<expr>, 1, null, 'IGNORE NULLS') (ein String-Argument)
  10. Kein ignore nulls
  11. Kein from last
  12. Kein ignore nulls • Kein from last

Common Table Expressions (with [recursive])

Die nächste wichtige Erweiterung in MySQL 8.0 sind die sogenannten Common Table Expressions (CTEs oder die with [recursive]-Klausel). Wichtige Anwendungsfälle sind das durchwandern von Graphen mit einer einzelnen Abfrage, eine beliebige Anzahl an Zeilen generieren, CSV-Strings in Zeilen wandeln (umgekehrtes listagg / group_concat) oder einfach literarisches SQL.

Auch hier schließt der Erstwurf von MySQL gleich zur Spitze auf.

BigQueryaDb2 (LUW)bMariaDBMySQLOracle DBcPostgreSQLeSQL ServercdeSQLiteewith auf oberster Ebenewith in Unterabfragenwith recursivefetch first in nicht-rek. Unterabf.insert … with … selectwith verdeckt Schema-Objektewith impliziert kein recursiveViews umgehen withQualifizierte Namen umgehen with
  1. Ohne Spaltenliste: WITH RECURSIVE query_name AS (SELECT…)
  2. Ohne dem Schlüsselwort Recursive • Kein Join im rekursiven Zeit – verwendet stattdessen einen Komma-Join (,)
  3. Ohne dem Schlüsselwort Recursive
  4. Alternative: row_number() over() verwenden, um Top-N-Filter umzusetzen
  5. Unterstützt eine proprietäre Syntax with … insert … select

Andere Standard-SQL-Funktionen

Neben Window-Funktionen und der With-Klausel hat MySQL 8.0 auch einige andere Standard-Funktionen eingeführt. Im Vergleich zu den vorherigen Beiden sind diese aber eher unspektakulär.

BigQueryDb2 (LUW)jMariaDBaehMySQLbfhklOracle DBchjPostgreSQLdgmSQL ServerijnSQLiteJSON_OBJECTAGGJSON_ARRAYAGGJSON_TABLEGROUPING-FunktionSpaltennamen in der FROM-Klausel
  1. Standardsyntax nicht unterstützt. Verwendet Komma (,) um Attributnamen und Werte zu trennen. Keine on null-Spezifikation
  2. Auch für MySQL 5.7.22 • Standardsyntax nicht unterstützt. Verwendet Komma (,) um Attributnamen und Werte zu trennen. Keine on null-Spezifikation
  3. Keine Doppelpunktsyntax (T814)
  4. Keine Doppelpunktsyntax (T814) • Kein (T830): [with|without] unique [keys]
  5. Keine order by-Klausel
  6. Keine order by-Klausel • Auch für MySQL 5.7.22
  7. Hat proprietäre Funktion json_agg
  8. Ohne Plan-Klausel
  9. Verwende OPENJSON
  10. Nur mit einem Argument
  11. Mit der proprietären WITH ROLLUP-Klausel
  12. Nur für derived Tables
  13. Akzeptiert weniger Spalten in der <derived column list> als in der Tabelle
  14. Nicht für normale Tabellen und Views

Wie man unten sehen kann, treibt Oracle den standardkonformen JSON-Support voran. Aktuell sind die Oracle-Datenbank und MySQL in diesem Bereich führend (nicht vergessen: beide aus dem Hause Oracle). Die Funktionen json_objectagg und json_arrayagg wurden sogar auf MySQL 5.7.22 rückportiert. Es ist jedoch auffällig, dass MySQL bei diesen Funktionen nicht die Standard-Syntax umgesetzt hat. Zusätze wie z. B. eine Order-By-Klausel werden grundsätzlich nicht unterstützt. Json_objectagg akzeptiert weder die Schlüsselworte key und value noch den Doppelpunkt (:) um die Attributnamen von den Werten zu trennen. Es scheint so, als würde MySQL diese Funktionen als normale Funktionsaufrufe behandeln – nicht entsprechend der Syntax des Standards.

Ich finde es auch interessant, dass json_arrayagg mit Null-Werten genauso falsch umgeht wie die Oracle-Datenbank (das Standardverhalten ist absent on null6). Wenn man dieselbe Abweichung in zwei vermeintlich unabhängigen Produkten sieht ist das immer interessant. In diesem Fall kommen beide vom selben Hersteller – das fügt dem ganzen noch das gewisse Etwas hinzu.

Die beiden letzten Funktionen aus der Auflistung, die Grouping-Funktion (gehört zu rollup) und Spaltennamen in der From-Klausel Lösen sehr spezielle Probleme. Die MySQL 8.0 Umsetzung kann mit anderen Datenbanken mithalten.

Darüber hinaus führt MySQL 8.0 auch Rollen ein. Der Grund, warum diese in der Matrix fehlen, ist einfach: Mein selbst gebautes Werkzeug zur Erstellung dieser Matrizen kann aktuell nicht mehrere Benutzer nebeneinander verwenden. Das heißt, ich kann Zugriffsrechte aktuell nicht testen. Das wird aber auch noch kommen – bleib dran.

Andere Interessante Neuerungen

Zum Abschluss möchte ich auch noch ein paar Neuerungen erwähnen, die nichts mit dem SQL-Standard zu tun haben.

Eine davon handelt von der Desc-Angabe bei create index:

CREATE INDEX … ON … (<column> [ASC|DESC], …)

Die meisten – wenn nicht alle – Datenbanken verwenden beim Anlegen eines Indexes dieselbe Sortierung wie bei der order by-Klausel. Die Voreinstellung ist also Aufsteigend. Manchmal ist es aber notwendig einzelne Spalten eines Indexes gegenläufig zu sortieren. Dafür verwendet man dann desc. Die MySQL 5.7 Dokumentation sagt dazu folgendes:

Eine index_col_name-Spezifikation kann auf ASC oder DESC enden. Diese Schlüsselworte sind für künftige Erweiterungen erlaubt, um Indexwerte steigend oder fallend zu speichern. Derzeit werden sie erkannt aber ignoriert; Indexwerte werden immer in steigender Reihenfolge gespeichert.

„Werden erkannt aber ignoriert“. Um genauer zu sein werden sie ohne jegliche Warnung ignoriert. Analog zu Check-Constraints.

Das ist in MySQL 8.0 behoben. Jetzt gibt es eine Warnung. Keine Panik – nur ein Spaß. Desc wird nun berücksichtigt.

Natürlich gibt es in MySQL 8.0 unzählige weitere Verbesserungen. Der Artikel „What’s New in MySQL 8.0?“ gibt einen sehr guten Überblick. Ein Vorgeschmack:

20 Jahre SQL-Evolution kann man nicht an einem Tag nachholen. Abonniere den Newsletter via E-Mail, Twitter oder RSS, um sukzessive aufzuholen und modern-sql.com am Radar zu behalten.

Über den Autor

Foto von Markus Winand

Markus Winand gibt auf modern-sql.com Einblick in SQL und zeigt, wie es von verschiedenen Systemen unterstützt wird. Zuvor machte er use-the-index-luke.com, was er noch immer wartet. Markus kann als Trainer, Sprecher und Berater auf winand.at engagiert werden.

Sein Buch kaufen

Titelbild von „SQL Performance Explained“: Eichhörnchen läuft durchs Grass

Die Essenz: SQL-Tuning auf 200 Seiten

Jetzt Kaufen
(Taschenbuch und/oder PDF)

Sein Training

Markus verwandelt veraltetes SQL-92-Wissen in solides und zeitgemäßes SQL-Know-how

Erfahren Sie mehr»

Fußnoten

  1. Ich persönlich folge in dieser Frage dem Argument von Chris Date: „Domains Can Conatain Anything!“ [„Date on Database: Writings 2000-2006“;ISBN 978-1590597460]. Ein Wert muss nicht mehr „atomar“ sein.

  2. Ich fürchte, dass viele Entwickler es bevorzugen mit der neusten und umjubelten Technologie eines Internetgiganten spielen, als etwas mehr über modernes SQL zu lernen.

  3. Tatsächlicher Titel: MySQL vs PostgreSQL - Why you shouldn’t use MySQL.

  4. Wenn man alte Versionen migriert hat ohne die neuen Standardwerte in die Konfiguration zu übernehmen, kann man manche Probleme aus der WAT-Vortrag noch immer haben.

  5. Leider ein wichtigerer Sprung als ein neuer SQL-Standard.

  6. Für die neugierigen: Oracle hat viel Energie auf die Verbesserung der MySQL-Basis verwendet. Ein hervorragender grund sich etwas langsamer zu bewegen.

  7. SQL-2:2016 §10.11 SR5a.

Mit Markus Winand verbinden

Markus Winand auf LinkedInMarkus Winand auf XINGMarkus Winand auf Twitter
„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 und DSGVO | CC-BY-NC-ND 3.0 Lizenz