Hash-Indexe in Postgres sind ein Spezialfall: sie unterstützen ausschließlich Gleichheits-Vergleiche, sind aber bei sehr langen Werten kompakter und schneller als B-tree. Lange Zeit waren sie nicht WAL-geloggt und damit für Production unbrauchbar — seit PG 10 ist das gefixt. Trotzdem bleibt B-tree fast immer die bessere Wahl.
Erstellen
CREATE INDEX users_email_hash_idx ON users USING hash (email);USING hash ist Pflicht — ohne wäre's ein B-tree.
Wann lohnt sich Hash gegenüber B-tree?
| Kriterium | Hash | B-tree |
|---|---|---|
=-Vergleich | Sehr schnell | Sehr schnell |
<, >, BETWEEN, ORDER BY | Nicht möglich | Ja |
| Eindeutigkeit (UNIQUE) | Nein | Ja |
| Größe bei langen Werten | Konstant | Wächst |
| Größe bei kurzen Werten | Vergleichbar | Vergleichbar |
| Constraint-Indexe (PK, FK) | Nein | Ja |
Hash ist nur dann besser, wenn:
- Du nur Gleichheit brauchst (kein Range, kein ORDER BY)
- Die indizierten Werte lang sind (z. B. lange Hashes, große Texte als Schlüssel)
- Du keine UNIQUE-Constraint brauchst
In der Praxis trifft das selten zu. Faustregel: bei Unsicherheit B-tree.
Die alte WAL-Falle
Vor PostgreSQL 10 war Hash-Indexe nicht WAL-geloggt:
- Bei Crash: Index war korrupt
- Auf Replicas: Index existierte nicht
- Bei Restore: Index musste manuell neu gebaut werden
Diese Falle gibt's seit PG 10 nicht mehr — Hash-Indexe sind voll WAL-fähig und replikationssicher. Ältere Doku oder Stack-Overflow-Antworten warnen oft noch davor; das ist veraltet.
Größenvergleich praktisch
-- Annahme: tabelle long_keys mit 1 Mio. Zeilen, key = 200-Zeichen-String
CREATE INDEX btree_idx ON long_keys USING btree (key);
CREATE INDEX hash_idx ON long_keys USING hash (key);
SELECT
indexrelname AS name,
pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
WHERE indexrelname IN ('btree_idx','hash_idx');In typischen Tests: Hash ~30 % kleiner bei langen Werten, ähnlich groß bei kurzen. Bei sehr großen Tabellen (Hunderte Millionen Zeilen) kann der Speicher-Unterschied relevant werden — sonst nicht.
Use-Cases — selten
Realistische Szenarien für Hash-Indexe:
- API-Tokens / Session-IDs: lange opake Strings, nur Gleichheits-Lookup
- Externe Schlüssel mit langen Hash-Werten (z. B. Git-Commit-SHAs)
- JSONB-Schlüssel mit langen String-Werten und reinen Equality-Checks
Selbst dann ist B-tree meist okay — und flexibler.
FAQ
Sollte ich Hash-Indexe in neuen Projekten einsetzen?
Pragmatisch: nein. B-tree macht alles was Hash macht — plus Range, ORDER BY, UNIQUE. Hash lohnt nur in spezifischen Performance-Setups, die du gemessen hast. Default ist B-tree.
Sind Hash-Indexe heute production-safe?
Ja, seit PG 10. Vorher waren sie nicht WAL-geloggt — bei Crash korrupt, auf Replicas fehlend. Wer das in alter Doku oder älteren Foren liest: das gilt nicht mehr.
Können Hash-Indexe UNIQUE sein?
Nein. CREATE UNIQUE INDEX … USING hash (...) schlägt fehl. Wer Eindeutigkeit braucht: B-tree. Da Eindeutigkeit häufig gewünscht ist, fällt damit ein wichtiger Use-Case für Hash weg.
Können Hash-Indexe Composite sein?
Nein, Hash-Indexe gehen nur auf eine Spalte. Bei Mehrspalten-Logik: B-tree.
Ist Hash schneller als B-tree für reine Equality?
In benchmarks oft minimal schneller — Faktor 1,1 bis 1,3 bei großen Datasets. Bei realistischen Workloads dominieren andere Faktoren (I/O, Caching, Plan-Wahl). Selten der Engpass.
Wie nutzt der Planner Hash-Indexe?
Nur für = und IN (einzelner Wert). Nicht für IN (a,b,c) mit mehreren Werten — da scannt Postgres den Index pro Wert separat. Bei IS NULL: nein, Hash-Indexe indizieren keine NULLs.