Mittwoch, 28. September 2011

Technische Unterschiede PostgreSQL, MySQL, MariaDB - Teil 8

Die vorangegangenen Teile dieser Artikelserie sind hier:

  1. http://miraspostgresqlwelt.blogspot.com/2011/08/technische-unterschiede-postgresql.html 
  2. http://miraspostgresqlwelt.blogspot.com/2011/08/technische-unterschiede-postgresql_30.html
  3. http://miraspostgresqlwelt.blogspot.com/2011/08/technische-unterschiede-postgresql_31.html
  4. http://miraspostgresqlwelt.blogspot.com/2011/09/technische-unterschiede-postgresql.html
  5. http://miraspostgresqlwelt.blogspot.com/2011/09/technische-unterschiede-postgresql_02.html
  6. http://miraspostgresqlwelt.blogspot.com/2011/09/technische-unterschiede-postgresql_06.html
  7. http://miraspostgresqlwelt.blogspot.com/2011/09/technische-unterschiede-postgresql_16.html
SQL-Standard

Sowohl PostgreSQL als auch MySQL versuchen so nah wie möglich am SQL-Standard zu bleiben und soviel wie möglich standardkonform zu implementieren. Beide sind daneben so ehrlich, dass sie in der Dokumentation herausstellen, wann sie vom Standard abweichen.

Die größte Abweichung vom Standard haben beide in der Implementierung von Identifier (Bezeichnern). Der Standard schreibt hier etwas von Identifier sollen per Default nur aus Großbuchstaben bestehen. PostgreSQL fand das schon im letzten Jahrhundert unzeitgemäß und implementierte genau das Gegenteil:

Bei PostgreSQL bestehen Identifier per Default nur aus Kleinbuchstaben. Somit ist PostgreSQL bei Identifiern case-insensitive.

MySQL kämpft hier mit weitaus größeren Problemen. Spalten- und Indexname sowie Namen für Funktionen und Prozeduren werden auch bei MySQL zu Kleinbuchstaben und sind case-insensitive. Trigger hingegen sind case-sensitive. Daneben hat MySQL ein weitaus größeres Problem mit Datenbank / Schema und Tabellennamen. Diese werden direkt auf dem Dateisystem abgelegt und es hängt vom Dateisystem ab, ob sie case-sensitive oder case-insensitive sind. Windows-Dateisysteme sind eigentlich immer case-insensitive und Unix-Dateisystem case-sensitive. Wird unter MacOS UFS genutzt, so sind Tabellen und Datenbanknamen case-sensitive. Wird das MacOS-Dateisystem HFS+ genutzt, sind sie case-insensitive. Durch setzen von lower_case_table_names kann das Verhalten geändert werden.

Als Sprachen, die zur Programmierung von Funktionen und Prozeduren verwendet werden, hat sich MySQL als einziges, der gängigen Systeme an den SQL Standard gehalten und SQL implementiert. Die SQL-Implementierung in PostgreSQL ist eher spärlich und beschränkt sich auf die ganz rudimentären Dinge.

PostgreSQL hat jedoch die eigene Sprache Pl/PgSQL implementiert, mit der sich auch komplexe Funktionen und Prozeduren schreiben lassen.

Mir persönlich ist noch keine produktive Datenbank mit Funktionen und Prozeduren begegnet, in der ich die Funktionen / Prozeduren nicht hätte sowohl in SQL als auch in Pl/PgSQL zusammenstricken können.

Mir sind sowohl in MySQL schon Funktionen / Prozeduren begegnet, bei denen ich mir dachte, dass wäre mit Pl/PgSQL einfacher gewesen als auch Funktionen in PostgreSQL bei denen die Umsetzung in SQL einfacher gewesen wäre. Daher denke ich, SQL versus Pl/PgSQL ist lediglich eine Frage der Gewohnheit.

Anzumerken ist hier - der Hauptunterschied, den der SQL Standard zwischen Funktionen und Prozeduren festlegt ist, dass Prozeduren keinen Rückgabewert haben. PostgreSQL hat das so interpretiert und implementiert, dass Prozeduren einfach Funktionen sind, die VOID zurückgeben. Prozeduren werden daher bei PostgreSQL auch nicht mit CALL aufgerufen, sondern genauso behandelt, wie andere Funktionen auch. Als Beispiel:

SELECT prozedur() statt CALL prozedur()

Neben Pl/PgSQL bietet PostgreSQL noch eine Reihe von anderen Sprachen an, in denen Funktionen geschrieben werden können. Die Palette ist lang und enthält alle gängigen Programmiersprachen wie PHP, Perl, C, Java, Ruby, ....

MySQL bietet die Möglichkeit User Defined Functions in C zu schreiben. Das würde ich persönlich aber eher als Qual als als Wahl bezeichnen.

Beim Thema Funktionen und Prozeduren stellt sich auch schnell die Frage, wo die Logik sinnvoller aufgehoben ist. In der Anwendung selbst oder in der Datenbank:

Ich sah einst eine fürchterlich aufwendige Pl/SQL-Funktion (Oracle) die alle eingebenen Umlauten in HTML-Code (z.b. ä für ä) wandelte. Die Programmiersprache, in der die Anwendung geschrieben war, verfügte bereits schon über eine solche Funktion. Heisst, in der Anwendung selbst war es ein Einzeiler. Warum hier also die Datenbank bemühen, wenn die Anwendung das viel besser kann?

Datenbanklogik gehört in die Datenbank, Anwendungslogik in die Anwendung. Die Grenze hier ist manchmal grau.

Genauso häufig wie man bei vielen MySQL-Anwendungen schreien könnte, weil Datenbanklogik in die Anwendung gepackt wurde, könnte man bei PostgreSQL-Anwendungen schreien, weil Anwendungslogik in die Datenbank gepackt wurde.

Wer wirklich nur Datenbanklogik in die Datenbank packt, kommt mit SQL genauso weit, wie mit Pl/PgSQL.

Constraints sind Bedingungen. Der Standard sieht sechs Constraints vor:
  • Not NULL
  • Unique
  • Default
  • Primary Key
  • Foreign Key
  • Check
PostgreSQL hat alle implementiert, InnoDB alle bis auf Check Constraints.

Beide lösen die Implementierung von Primary Key als NOT NULL Constraint plus Unique Index. Beide lösen die Implementierung von Unique als Unique Index.

Wie wichtig oder unwichtig CHECK Constraints sind, ist anwendungsabhängig.

Check Constraints können häufig mehr Schaden als Nutzen.

Check Constraints helfen nur bei Eingaben - also bei INSERT und UPDATE.

In den meisten Fällen, werden die Eingaben schon in der Anwendung geprüft, bevor sie zur Datenbank geschickt werden. Ein häufiger Grund hierfür ist, SQL-Injections zu vermeiden.

Warum dann also ein Check-Constraint als Bremse einbauen, dass die Eingabe nochmals prüft?

Daneben sind Verbindungen bei PostgreSQL teuer. Warum also eine teure Verbindung aufmachen, um eine Eingaben prüfen zu lassen? Bei Fehlschlag
bräuchte ist dann, nach Eingabekorrektur, nochmals eine Verbindung nötig. Ist es da nicht sinnvoller, die Daten werden in der Anwendung geprüft und gleich richtig übergeben?

Ich persönlich habe bei PostgreSQL, abgesehen von Partitionierung, noch keinen Anwendungsfall für Check-Constraints gesehen, wo die Eingabeprüfung nicht besser in der Anwendung aufgehoben war.
  • NULL bedeutet unbestimmt / unbekannt
  • NULL ist weder 0 noch Leerstring noch 00-00-0000 00:00:00.
  • NULL ist weder gleich noch nicht gleich NULL, sondern NULL.
PostgreSQL ist hier standardkonform. Wird für eine Zelle nichts angegeben und ist die Spalte nicht NOT NULL, so ist die Zelle NULL.

Das ist für die meisten Datentypen bei MySQL auch so. Allerdings kann MySQL mit NULL im Datentyp timestamp nicht umgehen. Hier ist per Default im ersten Timestamp der Default current_timestamp und in folgenden 00-00-0000 00:00:00. Der Datentyp datetime kann mit NULL umgehen und sollte verwendet werden, wenn das Verhalten von Timestamp missfällt.

Indexe sind nicht SQL Standard. Beide, sowohl PostgreSQL als auch MySQL behelfen sich mit Indexen wenn es um UNIQUE Constraints geht. Der Primary Key ist ein Zusammenschluß aus NOT NULL und UNIQUE Constraint. Daher wird hier sowohl für UNIQUE als auch für PRIMARY KEY ein Unique Index angelegt.

Zusätzlich legt InnoDB für jeden Foreign Key automatisch einen Index an.

Fortsetzung folgt ....

Keine Kommentare:

Kommentar veröffentlichen