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

SQL
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?

KriteriumHashB-tree
=-VergleichSehr schnellSehr schnell
<, >, BETWEEN, ORDER BYNicht möglichJa
Eindeutigkeit (UNIQUE)NeinJa
Größe bei langen WertenKonstantWächst
Größe bei kurzen WertenVergleichbarVergleichbar
Constraint-Indexe (PK, FK)NeinJa

Hash ist nur dann besser, wenn:

  1. Du nur Gleichheit brauchst (kein Range, kein ORDER BY)
  2. Die indizierten Werte lang sind (z. B. lange Hashes, große Texte als Schlüssel)
  3. 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

SQL Beide Indexe anlegen, vergleichen
-- 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.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Indexes

Zur Übersicht