SQL Datenbanken

SQL-Datenbanken sind die „Arbeitspferde“ für strukturierte Daten: Bestellungen, Benutzer, Buchhaltung, Lager, Logs mit Struktur, Rechteverwaltung und vieles mehr. Sie sind besonders stark, wenn Daten Beziehungen haben und du verlässliche Konsistenz brauchst.

Ziel: Verständlich + praxistauglich Fokus: JOINs, Indexe, ACID, Performance Stand: 09.02.2026
Merksatz: SQL ist nicht „kompliziert“, sondern präzise: Du beschreibst, welche Daten du willst – das System entscheidet, wie es sie effizient findet.
Inhalt (per Klick springen)

1) Grundlagen: Tabellen, Zeilen, Spalten

In relationalen Datenbanken werden Daten in Tabellen gespeichert. Eine Tabelle hat Spalten (Attribute) und Zeilen (Datensätze). Jede Spalte hat einen Datentyp (z. B. Zahl, Text, Datum).

Für Laien

Stell dir eine Excel-Tabelle vor – nur robust, parallel nutzbar, mit Regeln (Constraints) und für sehr große Datenmengen optimiert.

Für Profis

Relationale Systeme erzwingen Schema-Constraints (je nach DB mehr/ weniger strikt) und unterstützen deklarative Abfragen, Optimierung über Query-Planner, Index-Strukturen und Transaktions-Isolation.

CREATE TABLE users ( id BIGINT PRIMARY KEY, email TEXT NOT NULL UNIQUE, created_at TIMESTAMP NOT NULL );

2) Modellierung: Primär-/Fremdschlüssel & Beziehungen

Der wichtigste Unterschied zu „nur Tabellen“ ist: SQL-Datenbanken können Beziehungen sauber abbilden. Dafür nutzt man Primärschlüssel (eindeutige Identifikation) und Fremdschlüssel (Verweise).

Beziehung Beispiel Wie abbilden? Wichtigster Punkt
1 : 1 user ↔ user_profile Profil-Tabelle mit UNIQUE-FK Trennung sensibler / optionaler Daten
1 : n user → orders orders.user_id als FK Sehr häufig im Business
n : m users ↔ roles Zwischentabelle (user_roles) Join-Table ist Standard
CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL REFERENCES users(id), total_cents INT NOT NULL, created_at TIMESTAMP NOT NULL );
Praxis-Tipp: Fremdschlüssel schützen Datenqualität. Ohne FK landen schnell „verwaiste“ Datensätze in der DB (z. B. Orders ohne User).

3) Normalisierung (1NF–3NF) – wozu?

Normalisierung bedeutet: Daten so strukturieren, dass du Wiederholungen vermeidest und Änderungen sauber bleiben. Ziel ist nicht „akademisch perfekt“, sondern: weniger Fehler und weniger widersprüchliche Daten.

Typischer Anfängerfehler

Adressen oder Produktinfos werden mehrfach kopiert (z. B. in jeder Bestellung). Später ändert sich etwas – und du hast 20 unterschiedliche Stände.

Praktische Faustregel

Häufige, wiederverwendete Dinge bekommen eigene Tabellen (z. B. products, customers). „Beziehungsdaten“ kommen in Join-Tabellen.

Wichtig: Normalisierung und Performance sind kein Widerspruch. Du kannst normalisiert modellieren und trotzdem schnell sein – über Indexe, gute Queries und ggf. gezielte Denormalisierung dort, wo es wirklich nötig ist.

4) JOINs: so setzt du Beziehungen in Abfragen um

JOINs verbinden Tabellen. Damit kannst du z. B. „alle Bestellungen mit User-E-Mail“ abfragen, ohne Daten doppelt zu speichern.

JOIN Einfach erklärt Wann nutzen? Typischer Stolperstein
INNER JOIN Nur Treffer in beiden Tabellen Wenn Beziehung zwingend ist Fehlende Zeilen verschwinden
LEFT JOIN Alles links, rechts optional Wenn du auch „ohne Beziehung“ sehen willst WHERE auf rechter Tabelle kann LEFT JOIN „kaputt machen“
SELECT o.id, o.total_cents, u.email FROM orders o JOIN users u ON u.id = o.user_id WHERE o.total_cents >= 5000 ORDER BY o.created_at DESC;
LEFT JOIN Stolperstein: Wenn du nach einem LEFT JOIN in der WHERE-Klausel auf Spalten der rechten Tabelle filterst, wird es oft faktisch wieder ein INNER JOIN. Besser: Filter in die JOIN-Bedingung oder sauber mit IS NULL/IS NOT NULL arbeiten.

5) Indexe: schneller lesen, teurer schreiben

Indexe sind Datenstrukturen, die das Finden von Zeilen beschleunigen. Ohne Index kann eine DB viele Zeilen „durchscannen“. Mit Index kann sie schneller springen (z. B. B-Tree bei vielen Systemen).

Wann Indexe helfen

  • Spalten in WHERE / JOIN-Bedingungen
  • ORDER BY / GROUP BY (je nach DB/Index)
  • Hohe Datenmengen + selektive Filter

Wann Indexe schaden

  • Sehr schreiblastige Tabellen (viele INSERT/UPDATE)
  • Index auf Spalte mit sehr wenig Varianz (z. B. boolean)
  • Zu viele „blind“ angelegte Indexe
CREATE INDEX idx_orders_user_created ON orders (user_id, created_at DESC);

6) ACID & Transaktionen: Daten bleiben korrekt

Transaktionen bündeln mehrere SQL-Operationen zu einer Einheit. Entweder alles wird gespeichert – oder nichts. Das ist essenziell für Geld, Bestände, Buchungen, Statuswechsel.

ACID Bedeutung Einfach erklärt
Atomicity Alles oder nichts Keine halbfertigen Änderungen
Consistency Korrekte Zustände Constraints bleiben gültig
Isolation Abschirmung Parallele Transaktionen stören sich nicht unkontrolliert
Durability Dauerhaftigkeit Nach COMMIT bleibt es auch nach Crash erhalten
BEGIN; UPDATE accounts SET balance_cents = balance_cents - 2500 WHERE id = 10; UPDATE accounts SET balance_cents = balance_cents + 2500 WHERE id = 20; COMMIT;
Wichtig: Ohne Transaktion kann ein Crash zwischen den Aktualisierungen zu „Geld verschwunden“ oder „doppelt gebucht“ führen.

7) Isolation & Locks: warum parallele Nutzer tricky sind

Wenn 100 Nutzer gleichzeitig bestellen, greifen mehrere Transaktionen parallel auf gleiche Daten zu. Die DB sorgt über Isolation/Locks dafür, dass es nicht zu kaputten Zuständen kommt.

Typische Probleme

  • Lost Updates: Zwei Aktualisierungen überschreiben sich
  • Dirty Read: Lesen von uncommitted Daten
  • Phantom Reads: Ergebnis ändert sich während der Transaktion

Praktische Gegenmittel

  • Passendes Isolation Level wählen
  • Optimistic Locking (Version-Spalte)
  • Pessimistic Locking (SELECT ... FOR UPDATE)
Praxis-Tipp: Viele Deadlocks kommen von „uneinheitlicher Reihenfolge“. Wenn mehrere Tabellen gesperrt werden, immer in gleicher Reihenfolge sperren.

8) Performance: Query-Planner, EXPLAIN, typische Fehler

SQL ist deklarativ – du sagst was du willst. Der Query-Planner entscheidet, wie er es findet: welche Indexe, welche Join-Reihenfolge, welche Scans.

EXPLAIN (Grundidee)

Mit EXPLAIN (oder DB-spezifisch EXPLAIN ANALYZE) siehst du den Plan: Scans, Kosten, geschätzte Zeilen, tatsächliche Laufzeiten.

Typische Performance-Killer

  • WHERE auf nicht indizierten Spalten bei großen Tabellen
  • Funktionen auf Spalten in WHERE (macht Index oft wirkungslos)
  • SELECT * bei breiten Tabellen
  • Pagination mit OFFSET bei sehr großen Offsets

Schnelle Verbesserungen

  • Passende zusammengesetzte Indexe
  • Nur benötigte Spalten selektieren
  • Keyset Pagination (WHERE id < last_id)
  • Aggregationen vor Join prüfen
-- Statt: OFFSET 500000 (wird langsam) SELECT id, created_at FROM orders WHERE id < :last_id ORDER BY id DESC LIMIT 50;

9) Sicherheit: SQL Injection, Rollen, Least Privilege

Sicherheit ist nicht optional. Der häufigste Fehler ist SQL Injection durch String-Konkatenation. Dazu kommen Rechteverwaltung, Backups, Zugriffsschutz und Audit-Logs.

SQL Injection verhindern

  • Prepared Statements / Parameter verwenden
  • Keine SQL-Strings aus User-Input bauen
  • Whitelist statt Blacklist (z. B. Sortier-Spalten)

Least Privilege

  • App-User bekommt nur nötige Rechte (z. B. SELECT/INSERT, keine DROP)
  • Admin-Zugang getrennt, MFA/Netzwerkrestriktionen
  • Separate Rollen für Read-Only/Reporting
Goldene Regel: Wenn Nutzer-Input in SQL landet, dann nur als Parameter – niemals als zusammengesetzter String.

10) Betrieb: Backups, Migrationen, Replikation, Skalierung

Eine Datenbank ist nicht nur „Code“. Betrieb ist entscheidend: Backup/Restore, Aktualisierungen, Migrationen, Monitoring und Skalierung.

Backups (realistisch gedacht)

  • Regelmäßige Backups sind Pflicht – aber noch wichtiger ist Restore testen
  • Backup-Policy: Aufbewahrung, Verschlüsselung, Zugriff
  • RPO/RTO definieren (wie viel Verlust / wie schnell wieder online?)

Skalierung

  • Vertikal: mehr CPU/RAM/IO (oft der schnellste Gewinn)
  • Read Replicas: Lesen auslagern
  • Caching: häufige Reads (z. B. Redis)
  • Sharding: Daten aufteilen (komplex, aber effektiv)
Migrationen: Schema-Änderungen gehören versioniert wie Code. In Live-Systemen: migrations „online-friendly“ planen (z. B. Spalte hinzufügen, backfill, dann switch).

11) Praxis: Checklisten & typische Mini-Architekturen

Checkliste: Neue Tabelle

  • Primärschlüssel + sinnvolle Datentypen
  • NOT NULL / UNIQUE / CHECK Constraints
  • Fremdschlüssel für Beziehungen
  • Indexe nach echten Abfragen planen
  • Migration + Rollback-Plan

Checkliste: Query wird langsam

  • EXPLAIN/Plan ansehen
  • Filter/Join-Spalten indizieren
  • SELECT * vermeiden
  • Pagination optimieren
  • Datenverteilung prüfen (Skew)

Typische Architektur (verständlich)

API/BackendDB (Transaktionen, Constraints) → optional Cache (Reads) → optional Read Replica (Reporting). Wichtig: Das Datenmodell ist die „Wahrheit“ – nicht der Cache.

12) FAQ

Was ist der Unterschied zwischen SQL und einer SQL-Datenbank?

SQL ist die Sprache. Die Datenbank ist das System, das Daten speichert und SQL ausführt (z. B. PostgreSQL, MySQL, SQL Server).

Wann sollte ich NoSQL statt SQL nehmen?

Wenn du sehr flexible Schemas brauchst, extrem hohe Schreiblasten oder spezielle Modelle (Dokument/Key-Value/Graph). Bei starken Beziehungen und Konsistenz ist SQL oft die beste Wahl.

Muss ich immer normalisieren?

Normalisierung ist der sichere Start. Denormalisierung macht man gezielt, wenn Messungen zeigen, dass es nötig ist – und dann bewusst mit Index-/Cache-Strategie.

Wie verhindere ich SQL Injection?

Nur mit Parametern/Prepared Statements arbeiten. Nutzer-Input nie in SQL-Strings zusammenbauen. Rollen so einschränken, dass selbst im Worst Case wenig Schaden möglich ist.

Warum sind Indexe manchmal „nicht genutzt“?

Weil Filter nicht selektiv genug sind, Funktionen/CAST auf der Spalte liegen oder der Planner einen Scan als günstiger einschätzt. EXPLAIN zeigt dir, was passiert.

Hinweis: Diese Seite ist eine technische Orientierung. Details unterscheiden sich je Datenbank-System (PostgreSQL/MySQL/SQL Server/Oracle). Für produktive Entscheidungen: messen, planen, testen.