PostgreSQL vs MySQL: Welche Datenbank für Ihr Projekt?
Umfassender Vergleich der beiden beliebtesten relationalen Datenbanken. Features, Performance und Anwendungsfälle im Detail.

PostgreSQL vs MySQL: Der große Datenbank-Vergleich
PostgreSQL und MySQL sind die beiden dominierenden Open-Source-Datenbanken. Beide sind ausgereift, performant und weit verbreitet. Aber sie haben unterschiedliche Stärken – hier erfahren Sie, welche für Ihr Projekt die richtige Wahl ist.
Die Grundlagen
PostgreSQL
- Typ: Objektrelationale Datenbank
- Lizenz: PostgreSQL License (sehr permissiv)
- Erstveröffentlichung: 1996
- Philosophie: Feature-Reichheit und Standards-Konformität
MySQL
- Typ: Relationale Datenbank
- Lizenz: GPL (+ kommerzielle Lizenz von Oracle)
- Erstveröffentlichung: 1995
- Philosophie: Einfachheit und Performance
Feature-Vergleich
| Feature | PostgreSQL | MySQL |
|---|---|---|
| ACID-Compliance | Vollständig | Vollständig (mit InnoDB) |
| JSON-Unterstützung | Nativ (JSONB) | JSON-Datentyp |
| Full-Text Search | Eingebaut | Eingebaut |
| Replikation | Streaming + Logical | Master-Slave, Group |
| Partitionierung | Declarative | Range, List, Hash |
| Stored Procedures | PL/pgSQL, Python, Perl | SQL/PSM |
| Materialized Views | Ja | Nein |
| Foreign Data Wrappers | Ja | Nein |
| Window Functions | Umfassend | Ab 8.0 |
| CTEs (WITH) | Rekursiv | Ab 8.0 |
Wann PostgreSQL wählen?
1. Komplexe Abfragen
PostgreSQL glänzt bei komplexen analytischen Abfragen:
-- Hierarchische Abfrage mit rekursivem CTE WITH RECURSIVE org_tree AS ( SELECT id, name, manager_id, 1 AS level FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.id, e.name, e.manager_id, ot.level + 1 FROM employees e JOIN org_tree ot ON e.manager_id = ot.id ) SELECT * FROM org_tree ORDER BY level, name; -- Window Functions für Ranking SELECT product_name, category, price, RANK() OVER (PARTITION BY category ORDER BY price DESC) as price_rank, AVG(price) OVER (PARTITION BY category) as avg_category_price FROM products;
2. JSON-Daten
PostgreSQL's JSONB ist für semi-strukturierte Daten optimiert:
-- JSONB-Spalte mit Index CREATE TABLE orders ( id SERIAL PRIMARY KEY, customer_id INT, items JSONB, created_at TIMESTAMPTZ DEFAULT NOW() ); -- GIN-Index für schnelle JSON-Suche CREATE INDEX idx_orders_items ON orders USING GIN (items); -- Abfrage auf JSON-Daten SELECT * FROM orders WHERE items @> '[{"product_id": 123}]'; -- JSON aggregieren SELECT customer_id, jsonb_agg(items) as all_items FROM orders GROUP BY customer_id;
3. Geospatial (PostGIS)
Mit PostGIS ist PostgreSQL führend für Geodaten:
-- PostGIS aktivieren CREATE EXTENSION postgis; -- Standorte mit Geometrie CREATE TABLE locations ( id SERIAL PRIMARY KEY, name VARCHAR(100), geom GEOMETRY(Point, 4326) ); -- Alle Standorte im Umkreis von 5km SELECT name, ST_Distance(geom, 'POINT(11.5820 48.1351)'::geography) as distance FROM locations WHERE ST_DWithin(geom, 'POINT(11.5820 48.1351)'::geography, 5000) ORDER BY distance;
4. Datenintegrität
PostgreSQL bietet umfangreiche Constraints:
-- Partielle Unique Constraints CREATE UNIQUE INDEX idx_active_subscription ON subscriptions (user_id) WHERE status = 'active'; -- Check Constraints ALTER TABLE products ADD CONSTRAINT price_positive CHECK (price > 0); -- Exclusion Constraints (keine Überlappung) CREATE TABLE reservations ( room_id INT, during TSTZRANGE, EXCLUDE USING GIST (room_id WITH =, during WITH &&) );
Wann MySQL wählen?
1. Einfache CRUD-Operationen
MySQL ist optimiert für schnelle Lese-/Schreiboperationen:
-- Einfache Abfragen sind sehr schnell SELECT * FROM users WHERE id = 12345; SELECT * FROM products WHERE category_id = 5 LIMIT 20; -- Bulk Inserts INSERT INTO logs (message, level, created_at) VALUES ('Request processed', 'INFO', NOW()), ('Cache hit', 'DEBUG', NOW()), ('Response sent', 'INFO', NOW());
2. Web-Anwendungen (LAMP Stack)
MySQL ist perfekt integriert in:
- WordPress
- Drupal
- Magento
- Laravel
- Ruby on Rails
// PHP mit MySQL $pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass'); $stmt = $pdo->prepare('SELECT * FROM posts WHERE author_id = ?'); $stmt->execute([$authorId]); $posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
3. Read-Heavy Workloads
MySQL's Read-Replikation ist einfach einzurichten:
-- Auf dem Master SHOW MASTER STATUS; -- Auf dem Replica CHANGE REPLICATION SOURCE TO SOURCE_HOST='master.example.com', SOURCE_USER='repl_user', SOURCE_PASSWORD='password', SOURCE_LOG_FILE='mysql-bin.000001', SOURCE_LOG_POS=12345; START REPLICA;
4. Managed Services
Nahezu alle Cloud-Provider bieten MySQL:
- AWS RDS, Aurora MySQL
- Google Cloud SQL
- Azure Database for MySQL
- PlanetScale (Vitess-basiert)
Performance-Vergleich
Benchmarks (typische Ergebnisse)
| Szenario | PostgreSQL | MySQL |
|---|---|---|
| Einfaches SELECT by PK | 95k QPS | 110k QPS |
| Komplexe JOINs | Schneller | Langsamer |
| Bulk INSERT | 50k/s | 70k/s |
| JSON-Operationen | Schneller | Langsamer |
| Concurrent Writes | Besser | MVCC overhead |
Wichtig: Benchmarks variieren stark je nach Konfiguration, Hardware und Anwendungsfall. Testen Sie mit Ihren realen Daten!
Migration zwischen den Systemen
Von MySQL zu PostgreSQL
# Mit pgloader pgloader mysql://user:pass@localhost/dbname \ postgresql://user:pass@localhost/newdb # Oder manuell: # 1. Schema exportieren mysqldump --no-data dbname > schema.sql # 2. Schema konvertieren (Datentypen anpassen) # INT AUTO_INCREMENT → SERIAL # DATETIME → TIMESTAMP # TINYINT(1) → BOOLEAN # TEXT/MEDIUMTEXT/LONGTEXT → TEXT # 3. Daten exportieren/importieren mysqldump --no-create-info --complete-insert dbname > data.sql psql newdb < data.sql
Wichtige Unterschiede beim Migrieren
| MySQL | PostgreSQL |
|---|---|
| ``` backticks | "double quotes" |
| AUTO_INCREMENT | SERIAL / IDENTITY |
| LIMIT 10, 20 | LIMIT 20 OFFSET 10 |
| NOW() | NOW() / CURRENT_TIMESTAMP |
| IFNULL() | COALESCE() |
| GROUP_CONCAT() | STRING_AGG() |
| ENUM('a','b') | CREATE TYPE ... AS ENUM |
ORM-Unterstützung
Beide Datenbanken werden von allen großen ORMs unterstützt:
Node.js (Prisma)
// prisma/schema.prisma datasource db { provider = "postgresql" // oder "mysql" url = env("DATABASE_URL") } model User { id Int @id @default(autoincrement()) email String @unique posts Post[] } // Gleicher Code für beide Datenbanken const users = await prisma.user.findMany({ include: { posts: true } });
Python (SQLAlchemy)
from sqlalchemy import create_engine # PostgreSQL engine = create_engine('postgresql://user:pass@localhost/db') # MySQL engine = create_engine('mysql+pymysql://user:pass@localhost/db') # Rest des Codes bleibt identisch
Hosting-Optionen
PostgreSQL
| Anbieter | Besonderheit |
|---|---|
| Supabase | Firebase-Alternative mit Postgres |
| Neon | Serverless, Branching |
| Railway | Einfaches Deployment |
| AWS RDS | Enterprise-ready |
| Render | Kostenloser Tier |
MySQL
| Anbieter | Besonderheit |
|---|---|
| PlanetScale | Serverless, Git-like Branching |
| AWS Aurora | MySQL-kompatibel, hochverfügbar |
| DigitalOcean | Einfache Managed DB |
| Vitess | Horizontal Scaling |
Fazit und Empfehlung
PostgreSQL wenn:
- Komplexe Datenmodelle und Abfragen
- JSON-Daten wichtig sind
- Geodaten benötigt werden
- Datenintegrität höchste Priorität hat
- Sie erweiterte SQL-Features nutzen wollen
MySQL wenn:
- Einfache CRUD-Anwendungen
- Bestehende MySQL-Expertise im Team
- WordPress/Drupal/Magento
- Maximale Read-Performance gefragt
- Breite Cloud-Unterstützung wichtig
Unsere Praxis bei Balane Tech
Wir setzen primär PostgreSQL ein für:
- Neue Projekte
- Komplexe Business-Logik
- Anwendungen mit JSON-Daten
MySQL nutzen wir bei:
- Bestehenden WordPress-Projekten
- Kundenanforderung für MySQL
- Einfachen Web-Anwendungen
Beide Datenbanken sind exzellent. Die "richtige" Wahl hängt von Ihren spezifischen Anforderungen ab.


