Zum Inhalt springen
SQL Anfänger 30 min

Indizes & Performance

Lerne, wie Indizes deine SQL-Abfragen um ein Vielfaches beschleunigen - wann du sie brauchst und wie du sie richtig einsetzt.

Aktualisiert:

Wenn deine Datenbank waechst, werden Abfragen langsamer. Indizes sind das wichtigste Werkzeug, um die Performance deiner Abfragen dramatisch zu verbessern - manchmal von Minuten auf Millisekunden.

Was ist ein Index?

Stell dir ein Buch ohne Inhaltsverzeichnis vor. Um ein bestimmtes Thema zu finden, muesste man jede Seite durchblaettern. Ein Index (Inhaltsverzeichnis) zeigt dir sofort, auf welcher Seite das Thema steht.

Genauso funktioniert ein Datenbank-Index: Statt alle Zeilen zu durchsuchen, findet die Datenbank die gesuchten Daten direkt.

Ohne Index

-- Die Datenbank muss ALLE Zeilen durchsuchen (Full Table Scan)
SELECT * FROM kunden WHERE email = 'anna@example.com';
-- Bei 1 Million Kunden: Alle 1 Million Zeilen pruefen

Mit Index

-- Index auf die email-Spalte erstellen
CREATE INDEX idx_kunden_email ON kunden(email);

-- Jetzt findet die Datenbank den Kunden direkt
SELECT * FROM kunden WHERE email = 'anna@example.com';
-- Bei 1 Million Kunden: Nur wenige Lookups noetig

Index erstellen

CREATE INDEX index_name ON tabellenname(spalte);

Einfacher Index

-- Index auf eine Spalte
CREATE INDEX idx_kunden_stadt ON kunden(stadt);

-- Jetzt sind Abfragen nach Stadt schnell:
SELECT * FROM kunden WHERE stadt = 'Berlin';

Zusammengesetzter Index (Composite Index)

-- Index auf mehrere Spalten
CREATE INDEX idx_bestellungen_kunde_datum
ON bestellungen(kunden_id, bestelldatum);

-- Beschleunigt Abfragen, die nach Kunde UND Datum filtern:
SELECT * FROM bestellungen
WHERE kunden_id = 1 AND bestelldatum >= '2026-01-01';

UNIQUE Index

-- Eindeutiger Index (verhindert Duplikate + beschleunigt Suche)
CREATE UNIQUE INDEX idx_kunden_email_unique ON kunden(email);

Ein UNIQUE Index ist automatisch auch ein normaler Index. Wenn du einen UNIQUE Constraint auf eine Spalte setzt, erstellt die Datenbank automatisch einen UNIQUE Index.

Wann brauche ich einen Index?

Index SINNVOLL fuer:

SituationBeispiel
WHERE-BedingungenWHERE stadt = 'Berlin'
JOIN-SpaltenON b.kunden_id = k.id
ORDER BYORDER BY bestelldatum DESC
Spalten mit UNIQUE Constraintemail UNIQUE
Fremdschluesselkunden_id REFERENCES kunden(id)
Haeufig gesuchte SpaltenWHERE status = 'offen'

Index NICHT sinnvoll fuer:

SituationGrund
Sehr kleine TabellenFull Table Scan ist schneller
Spalten, die selten in WHERE stehenIndex wird nicht genutzt
Spalten mit wenigen verschiedenen Wertenz.B. geschlecht (nur M/W/D)
Tabellen, die hauptsaechlich geschrieben werdenIndex verlangsamt INSERT/UPDATE

EXPLAIN - Ausfuehrungsplan analysieren

EXPLAIN zeigt dir, wie die Datenbank deine Abfrage ausfuehrt:

-- PostgreSQL:
EXPLAIN SELECT * FROM kunden WHERE stadt = 'Berlin';

-- PostgreSQL mit tatsaechlicher Ausfuehrungszeit:
EXPLAIN ANALYZE SELECT * FROM kunden WHERE stadt = 'Berlin';

-- SQLite:
EXPLAIN QUERY PLAN SELECT * FROM kunden WHERE stadt = 'Berlin';

Ergebnis ohne Index (PostgreSQL)

Seq Scan on kunden  (cost=0.00..1.06 rows=2 width=...)
  Filter: (stadt = 'Berlin'::text)

Seq Scan = Sequential Scan = Alle Zeilen werden durchsucht (langsam bei vielen Daten).

Ergebnis mit Index (PostgreSQL)

Index Scan using idx_kunden_stadt on kunden  (cost=0.14..8.16 rows=2 width=...)
  Index Cond: (stadt = 'Berlin'::text)

Index Scan = Der Index wird benutzt (schnell).

Arten von Indizes

B-Tree Index (Standard)

Der Standard-Index, gut fuer Vergleiche (=, <, >, <=, >=, BETWEEN):

CREATE INDEX idx_produkte_preis ON produkte(preis);

-- Nutzt den Index:
SELECT * FROM produkte WHERE preis < 50;
SELECT * FROM produkte WHERE preis BETWEEN 20 AND 80;
SELECT * FROM produkte ORDER BY preis;

Hash Index (PostgreSQL)

Schneller als B-Tree fuer Gleichheitsvergleiche, aber nur dafuer:

-- PostgreSQL:
CREATE INDEX idx_kunden_email_hash ON kunden USING HASH (email);

-- Nutzt den Index (nur =):
SELECT * FROM kunden WHERE email = 'anna@example.com';

-- Nutzt den Index NICHT:
SELECT * FROM kunden WHERE email LIKE 'anna%';

Partial Index (Teilindex)

Ein Index, der nur einen Teil der Daten umfasst:

-- Index nur fuer offene Bestellungen
CREATE INDEX idx_bestellungen_offen
ON bestellungen(bestelldatum)
WHERE status = 'offen';

-- Wird genutzt bei:
SELECT * FROM bestellungen WHERE status = 'offen' AND bestelldatum > '2026-03-01';

Partial Indexes sind kleiner und schneller, weil sie nicht alle Zeilen indexieren.

Expression Index

Index auf berechneten Ausdruecken:

-- PostgreSQL: Index auf Kleinbuchstaben-E-Mail
CREATE INDEX idx_kunden_email_lower ON kunden(LOWER(email));

-- Wird genutzt bei:
SELECT * FROM kunden WHERE LOWER(email) = 'anna@example.com';

Performance-Tipps

1. Die richtigen Spalten indexieren

-- Index auf die Spalten, die in WHERE, JOIN und ORDER BY stehen
CREATE INDEX idx_bestellungen_kunden_id ON bestellungen(kunden_id);
CREATE INDEX idx_bestellungen_status ON bestellungen(status);
CREATE INDEX idx_bestellpositionen_bestell_id ON bestellpositionen(bestell_id);
CREATE INDEX idx_bestellpositionen_produkt_id ON bestellpositionen(produkt_id);

2. Composite Index Reihenfolge beachten

-- Index auf (stadt, name)
CREATE INDEX idx_kunden_stadt_name ON kunden(stadt, name);

-- Nutzt den Index (stadt ist erste Spalte):
SELECT * FROM kunden WHERE stadt = 'Berlin';
SELECT * FROM kunden WHERE stadt = 'Berlin' AND name LIKE 'A%';

-- Nutzt den Index NICHT (name ohne stadt):
SELECT * FROM kunden WHERE name LIKE 'A%';

Regel: Ein zusammengesetzter Index wird nur genutzt, wenn die Abfrage von links nach rechts die Spalten des Index verwendet.

3. Index-Nutzung verhindern (Anti-Patterns)

-- Diese Abfragen koennen den Index NICHT nutzen:

-- Funktion auf indizierter Spalte:
SELECT * FROM kunden WHERE UPPER(stadt) = 'BERLIN';

-- Negation:
SELECT * FROM kunden WHERE stadt != 'Berlin';

-- LIKE mit fuehrendem Platzhalter:
SELECT * FROM kunden WHERE name LIKE '%Schmidt';

-- OR auf verschiedenen Spalten:
SELECT * FROM kunden WHERE stadt = 'Berlin' OR name = 'Max';

4. Zu viele Indizes vermeiden

Indizes haben auch Nachteile:

-- Jeder Index verlangsamt INSERT, UPDATE und DELETE!
-- Weil der Index bei jeder Aenderung aktualisiert werden muss.
OperationOhne IndexMit Index
SELECT (mit WHERE)LangsamSchnell
INSERTSchnellLangsamer
UPDATESchnellLangsamer
DELETESchnellLangsamer
SpeicherplatzWenigMehr

Faustregel: Indexiere nur Spalten, die haeufig in WHERE, JOIN und ORDER BY verwendet werden.

Index loeschen

DROP INDEX idx_kunden_stadt;

-- Sicherer:
DROP INDEX IF EXISTS idx_kunden_stadt;

Praxisbeispiel: Shop-Datenbank optimieren

-- Wichtigste Indizes fuer unseren Online-Shop:

-- 1. Kunden nach Stadt suchen
CREATE INDEX idx_kunden_stadt ON kunden(stadt);

-- 2. Bestellungen nach Kunde finden (FK Index)
CREATE INDEX idx_bestellungen_kunden_id ON bestellungen(kunden_id);

-- 3. Bestellungen nach Status filtern
CREATE INDEX idx_bestellungen_status ON bestellungen(status);

-- 4. Bestellungen nach Datum sortieren
CREATE INDEX idx_bestellungen_datum ON bestellungen(bestelldatum);

-- 5. Bestellpositionen schnell finden
CREATE INDEX idx_bp_bestell_id ON bestellpositionen(bestell_id);
CREATE INDEX idx_bp_produkt_id ON bestellpositionen(produkt_id);

-- 6. Produkte nach Kategorie filtern
CREATE INDEX idx_produkte_kategorie ON produkte(kategorie);

Was kommt als Naechstes?

Im naechsten Tutorial lernst du Window Functions kennen - eine fortgeschrittene SQL-Technik fuer komplexe Analysen und Rankings.

Zusammenfassung

  • Indizes beschleunigen SELECT-Abfragen dramatisch
  • Erstelle Indizes auf Spalten in WHERE, JOIN und ORDER BY
  • EXPLAIN zeigt dir, ob ein Index genutzt wird
  • Composite Indexes folgen der Links-nach-Rechts-Regel
  • Partial Indexes indexieren nur relevante Daten
  • Zu viele Indizes verlangsamen Schreiboperationen
  • Faustregel: Index fuer lesehaeufige, nicht fuer schreibhaeufige Spalten

Uebungen

  1. Index erstellen: Erstelle einen Index auf der kategorie-Spalte der Produkttabelle.
  2. EXPLAIN: Vergleiche den Ausfuehrungsplan einer Abfrage vor und nach dem Erstellen eines Index.
  3. Composite Index: Erstelle einen zusammengesetzten Index auf (kunden_id, bestelldatum) in der Bestellungen-Tabelle. Fuer welche Abfragen ist er nuetzlich?
  4. Partial Index: Erstelle einen Index, der nur offene Bestellungen umfasst.
  5. Analyse: Welche Indizes wuerdest du fuer eine Blog-Datenbank mit den Tabellen posts, kommentare und tags erstellen?
-- Loesung zu Uebung 1:
CREATE INDEX idx_produkte_kategorie ON produkte(kategorie);

-- Loesung zu Uebung 4 (PostgreSQL):
CREATE INDEX idx_offene_bestellungen
ON bestellungen(bestelldatum)
WHERE status = 'offen';

Pro-Tipp: Nutze EXPLAIN ANALYZE regelmaessig, um langsame Abfragen zu identifizieren. In PostgreSQL kannst du mit SET log_min_duration_statement = 1000; alle Abfragen loggen, die laenger als 1 Sekunde dauern. So findest du die Stellen, wo Indizes den groessten Unterschied machen.

Zurück zum SQL Kurs