Die meisten Vergleiche von Postgres und MySQL sind eine Feature-Checkliste von 2015 mit aktualisierten Jahreszahlen. Beide Datenbanken haben inzwischen das meiste nachgeholt, was die jeweils andere früher exklusiv hatte — die Checkliste sagt also fast nichts mehr aus.
Was sich weiterhin unterscheidet, liegt tiefer: wie Zeilen gespeichert werden, wie gleichzeitige Versionen dieser Zeilen verwaltet werden, was eine Verbindung kostet, und was passiert, wenn eine Migration auf halbem Weg scheitert. Diese Unterschiede tauchen in keiner Feature-Tabelle auf — und mit ihnen leben Sie täglich.

Die Antwort in 30 Sekunden
- Komplexe Abfragen, Analytik, JSON, Geodaten, Erweiterungen? Postgres.
- Sehr viele einfache Verbindungen, Zugriffe über Schlüssel, Read-Replicas? MySQL.
- Team beherrscht bereits eine der beiden? Diese. Ernsthaft.
- Grüne Wiese ohne Randbedingungen? Postgres, weil das Erweiterungs-Ökosystem später mehr Notausgänge bietet.
- Ein Prozess, kein Netzwerk, kein Betrieb? Keine von beiden — das ist SQLite.
Alles Weitere ist die Begründung.
Was sich unter der Haube wirklich unterscheidet
Speicherung: geclustert gegen Heap
Diese eine Entscheidung erklärt die meisten Performance-Unterschiede.
MySQL (InnoDB) clustert die Tabelle über den Primärschlüssel. Die Zeilendaten liegen physisch im Primärschlüsselindex. Ein Zugriff über den Primärschlüssel traversiert einen B-Baum — und Sie halten die Zeile in der Hand.
Der Preis: Sekundärindizes speichern den Primärschlüssel, keine Zeilenposition. Ein Zugriff über einen Sekundärindex traversiert also erst diesen Index bis zum Primärschlüssel und dann den Primärschlüsselindex bis zur Zeile. Zwei Traversierungen. Außerdem bläht ein breiter Primärschlüssel jeden Sekundärindex der Tabelle auf.
Postgres legt Zeilen in einem Heap ab — einem ungeordneten Haufen von Seiten — und jeder Index, auch der Primärschlüssel, zeigt dort hinein. Jeder Indexzugriff kostet einen zusätzlichen Zugriff auf die Zeile.
Der Vorteil: Alle Indizes sind gleichwertig, ein breiter Primärschlüssel belastet die übrigen nicht, und Postgres kann Index-Only-Scans nutzen, wenn die Visibility Map eine Seite als vollständig sichtbar meldet.
Praktisch heißt das: MySQL ist hervorragend in „gib mir die Zeile mit dieser ID”. Postgres ist ausgewogener, wenn Ihre Zugriffsmuster vielfältig sind.
MVCC: wo alte Zeilenversionen liegen
Beide liefern Leser, die Schreiber nie blockieren. Sie bezahlen es unterschiedlich.
Postgres schreibt eine neue Zeilenversion in die Tabelle selbst und lässt die alte liegen, bis VACUUM sie freigibt. Änderungsintensive Tabellen blähen dadurch auf, und ob Autovacuum hinterherkommt, ist eine reale Betriebsfrage, keine theoretische.
MySQL schreibt alte Versionen in Undo-Logs, die Tabelle bleibt also kompakt. Die Kosten wandern woandershin: Lang laufende Transaktionen lassen das Undo-Log wachsen, und ein Leser auf einem alten Snapshot muss sich durch diese Versionen zurückarbeiten.
Keiner der beiden Wege ist gratis. Postgres zwingt Sie, über Vacuum nachzudenken; MySQL über lange Transaktionen und Undo-Wachstum.
Verbindungen: Prozess gegen Thread
Postgres forkt einen Prozess pro Verbindung. Ein Prozess ist nicht billig. Einige hundert überwiegend untätige Verbindungen kosten echten Speicher, und vor jedem ernsthaften Deployment wollen Sie PgBouncer oder einen vergleichbaren Pooler. Serverless-Plattformen, die pro Request eine Verbindung öffnen, verschärfen das.
MySQL nutzt einen Thread pro Verbindung, was dramatisch günstiger ist. Tausende Verbindungen sind dort eine gewöhnliche Konfiguration.
Wenn Ihre Architektur viele kurzlebige Verbindungen öffnet und Sie nicht poolen können, entscheidet allein diese Tatsache womöglich Ihre Datenbankwahl.
Postgres vs. MySQL: Performance
Niemand kann Ihnen ehrlich sagen, welche schneller ist, weil sie bei unterschiedlichen Arbeitsformen schnell sind. Was jede tatsächlich begünstigt:

MySQL liegt tendenziell vorn bei:
- Punktzugriffen über den Primärschlüssel — eine Traversierung, Zeile da
- sehr hohen Verbindungszahlen
- einfachem OLTP mit hohem Volumen, wo der Ausführungsplan offensichtlich ist
- Leseskalierung über Replicas, mit ausgereifter Binlog-Replikation
Postgres liegt tendenziell vorn bei:
- komplexen Joins, Unterabfragen und Aggregationen — stärkerer Planer
- analytischen Abfragen neben dem transaktionalen Betrieb
- allem mit Teil-, Ausdrucks- oder abdeckenden Indizes
- Schreibmustern, die von
HOT-Updates ohne Index-Churn profitieren - JSON, Arrays, Geodaten und Vektoren — dank Erweiterungen
Ein Wort zu Benchmarks. Jede Zahl, die Sie lesen — auch jede, die ich veröffentlichen könnte — ist eine Last, ein Schema, ein Hardwareprofil, eine Konfiguration. Tuning verschiebt Ergebnisse stärker als die Wahl der Engine. Wenn Performance wirklich Ihr Entscheidungskriterium ist, messen Sie Ihre Abfragen auf Ihren Daten. Alles andere ist die Last von jemand anderem.
Wenn Sie nicht wählen, sondern optimieren: Die Techniken aus SQL-Query-Optimierung gelten für beide Engines.
Postgres vs. MySQL: Syntaxunterschiede
Der Abschnitt, der bei einer Portierung zählt. Diese Punkte brechen tatsächlich.
| Thema | Postgres | MySQL |
|---|---|---|
| String-Verkettung | 'a' || 'b' |
CONCAT('a','b') |
| Bezeichner quoten | "meine tabelle" |
`meine tabelle` |
| Auto-inkrementierender Schlüssel | GENERATED ALWAYS AS IDENTITY |
AUTO_INCREMENT |
| Upsert | INSERT ... ON CONFLICT DO UPDATE |
INSERT ... ON DUPLICATE KEY UPDATE |
| Eingefügte Zeile zurückgeben | INSERT ... RETURNING * |
nicht unterstützt |
| Boolean | echter BOOLEAN-Typ |
Alias für TINYINT(1) |
| String-Vergleich | standardmäßig case-sensitiv | in üblichen Kollationen case-insensitiv |
| Limit mit Offset | LIMIT 10 OFFSET 20 |
LIMIT 10 OFFSET 20 oder LIMIT 20, 10 |
| Aktueller Zeitstempel | NOW(), CURRENT_TIMESTAMP |
NOW(), CURRENT_TIMESTAMP |
| Arrays | native Array-Typen | nicht unterstützt |
| Regex-Vergleich | ~, ~* |
REGEXP, RLIKE |
Drei davon verursachen den meisten Schmerz:
RETURNING. Postgres gibt Ihnen die soeben geschriebene Zeile in derselben Anweisung zurück. MySQL unterstützt das nicht — Sie fügen ein und selektieren danach, also ein zweiter Roundtrip und ein Wettlauf, wenn Sie nicht aufpassen. MariaDB unterstützt es.
-- Postgres: eine AnweisungINSERT INTO users (email) VALUES ('a@b.com')RETURNING id, created_at;Groß-/Kleinschreibung. In Postgres findet WHERE email = 'Bob@x.com' ein gespeichertes bob@x.com nicht. In MySQL mit üblicher Kollation schon. Portierungen in beide Richtungen ändern das Verhalten stillschweigend, und der Fehler zeigt sich in Produktion als „Login geht manchmal nicht”.
Faltung ungequoteter Bezeichner. Postgres schreibt ungequotete Bezeichner klein, CREATE TABLE MyTable erzeugt also mytable. Sobald Sie etwas als "MyTable" quoten, müssen Sie es für immer quoten. Der übliche Rat — durchgehend lower_snake_case, niemals quoten — lohnt sich in beiden.
Betrieb: der Unterschied, den niemand erwähnt
Postgres beherrscht transaktionales DDL. Sie können Schemaänderungen in eine Transaktion packen und zurückrollen:
BEGIN;ALTER TABLE orders ADD COLUMN status text;-- hier scheitert etwasROLLBACK; -- die Spalte hat nie existiertMySQL committet bei DDL implizit. Eine Migration, die bei Schritt vier von sechs scheitert, hinterlässt drei angewandte Änderungen und keinen Rückweg außer einer handgeschriebenen Down-Migration.
Wer häufig Schemaänderungen ausrollt, spürt das im Alltag stärker als jeden Query-Benchmark.
Zwei weitere Betriebsnotizen:
- Erweiterungen. Postgres erlaubt PostGIS für Geodaten, pgvector für Embeddings, TimescaleDB für Zeitreihen — in derselben Datenbank, mit denselben Backups und denselben Transaktionen. MySQL hat keinen vergleichbaren Mechanismus. Falls Sie womöglich eine Vektordatenbank brauchen, zählt das.
- Replikation. MySQLs Binlog-Replikation ist alt, gut verstanden und hervorragend mit Werkzeugen versorgt. Postgres bietet physische Streaming-Replikation und logische Replikation; beides funktioniert gut, und die logische Replikation hat in jüngeren Releases deutlich zugelegt.
Wo SQLite hingehört
SQLite landet oft in diesem Vergleich, meist mit falschem Rahmen.
SQLite ist keine kleine Serverdatenbank, sondern eine Bibliothek in Ihrem Prozess. Kein Server, kein Port, keine Benutzerkonten, kein Netzwerk-Roundtrip — ein Funktionsaufruf liest eine Datei.
Das macht es hervorragend für:
- lokalen Anwendungszustand, Caches und Konfiguration
- Testsuites, wo eine Datenbank pro Test Mikrosekunden kostet
- Edge- und eingebettete Deployments
- leseintensive Lasten auf einer einzelnen Maschine
Und ungeeignet, sobald mehrere Anwendungsserver gleichzeitig schreiben müssen. SQLite serialisiert Schreiber: einer nach dem anderen.
Die ehrliche Regel: Fasst genau ein Prozess die Daten an, ist SQLite wahrscheinlich richtig — und die einfachste Antwort. Könnten es zwei sein, wollen Sie einen Server.
MariaDB gegen MySQL
MariaDB entstand nach Oracles Übernahme als MySQL-Fork. Jahre später ist „Drop-in-Ersatz” nicht mehr zutreffend.
Beide haben sich auseinanderentwickelt: getrennte Optimizer-Arbeit, unterschiedliche Storage-Engines, und auf jeder Seite Funktionen, die der anderen fehlen. MariaDB hat RETURNING, MySQL nicht. Die Versionsnummern korrespondieren überhaupt nicht mehr.
Treiber und einfache Dumps sind weitgehend austauschbar. Replikation zwischen beiden und neuere Syntax sind es nicht.
MariaDB für Community-Governance und den konkreten Funktionsumfang. MySQL, wenn Sie an Oracles Ökosystem, einem darauf aufbauenden verwalteten Angebot oder der exakten Replikationssemantik hängen.
Welche Versionen betreiben
Stand September 2026:
| Datenbank | Aktuell | Anmerkungen |
|---|---|---|
| PostgreSQL | 18 (18.6) | 19 in der Beta; 14 endet im Nov. 2026 |
| MySQL | 9.7 LTS (9.7.3) | 8.4 LTS bis 2029; 8.0 endete im Apr. 2026 |
| MariaDB | 12.3 LTS (12.3.3) | 11.8 und 11.4 LTS weiterhin unterstützt |
Zwei Handlungspunkte: Wer auf MySQL 8.0 ist, läuft ohne Support — planen Sie den Wechsel auf 8.4 oder 9.7. Wer auf Postgres 14 ist, hat Zeit bis November.
Postgres liefert jährlich eine Hauptversion mit fünf Jahren Support. MySQL teilt sich in quartalsweise Innovation-Releases und etwa zweijährliche LTS-Releases; betreiben Sie LTS, sofern Sie kein konkretes neues Feature brauchen.
Die Entscheidungstabelle
| Ihre Situation | Wahl |
|---|---|
| Komplexe Abfragen, Reporting neben OLTP | Postgres |
| Geodaten, Vektoren, Zeitreihen in einer Datenbank | Postgres — Erweiterungen |
| Häufige Schema-Migrationen | Postgres — transaktionales DDL |
| Tausende Verbindungen, kein Pooler möglich | MySQL |
| Key-Value-artiger Zugriff über Primärschlüssel | MySQL — geclusterter Index |
| Starke Leseskalierung über Replicas | MySQL — ausgereifte Binlog-Werkzeuge |
| Ein Prozess besitzt die Daten, kein Netzwerk | SQLite |
| Community-Governance statt Oracle | MariaDB oder Postgres |
| Team beherrscht eine davon tiefgehend | Diese |
Das Fazit
Die Feature-Lücke, die diese Debatte vor einem Jahrzehnt interessant machte, ist weitgehend geschlossen. Geblieben ist Strukturelles: geclusterte gegen Heap-Speicherung, alte Zeilenversionen in der Tabelle gegen Undo-Logs, ein Prozess gegen ein Thread pro Verbindung, und ob eine gescheiterte Migration zurückrollbar ist.
Diese vier Unterschiede prägen Ihren Betriebsalltag weit stärker als jede Feature-Checkliste. Entscheiden Sie danach — und danach, welche Ihr Team um drei Uhr nachts debuggen kann.
Und wenn Sie sich anhand eines Benchmarks entscheiden, den Sie nicht selbst gefahren haben, entscheiden Sie anhand der Last von jemand anderem.




Aus der Community
Diskussion im Fediverse
Antworten von Mastodon und Bluesky — direkt aus dem offenen Netz, ohne Tracking.
Antworten werden geladen …
Noch keine Antworten. Starte die Diskussion:
Antworten konnten gerade nicht geladen werden.