Indexierung in PostgreSQL ist eine Methode, um Daten in der Datenbank schnell zu finden. Wenn die Daten in deiner Tabelle Bücher wären, dann wäre ein Index wie ein Katalog in der Bibliothek, mit dem du schnell das richtige Buch nach Titel oder Autor findest. Mit JSONB ist das Ganze ein bisschen trickreicher, weil die Daten in einem strukturierten Format gespeichert werden und nicht als einzelne Zeilen und Spalten.
Wenn JSONB-Daten anfangen, die Größe von "Harry Potter ohne Bilder" zu erreichen, kann die Suche in dieser Struktur langsam werden. Zum Beispiel, wenn du alle Bestellungen finden willst, bei denen der Schlüssel "status" den Wert "delivered" hat, muss PostgreSQL alle Einträge durchgehen, um zu suchen. Das klingt nach einer Arbeit, die du sicher nicht von Hand machen willst, oder?
Hier kommen die Indizes GIN und BTREE ins Spiel – unsere Helden, die uns vor langen Wartezeiten retten!
Index-Typen für JSONB
GIN (Generalized Inverted Index)
Der GIN-Index ist speziell für strukturierte Daten wie Arrays und Objekte gemacht, was ihn perfekt für JSONB macht. Er indexiert nicht das ganze Objekt, sondern einzelne Schlüssel und Werte darin. Das bedeutet, dass du mit GIN schnell Einträge findest, die bestimmte Schlüssel, Werte oder Kombinationen enthalten.
Stell dir eine JSONB-Spalte mit folgenden Daten vor:
{"name": "Alice", "age": 25, "city": "Berlin"}
Der GIN-Index baut eine interne Struktur auf, in der die Schlüssel "name", "age" und "city" mit ihren Werten verknüpft sind. Wenn wir also nach "name": "Alice" suchen, weiß PostgreSQL schon, wo es suchen muss – es läuft nicht durch die ganze Tabelle.
BTREE
Der BTREE-Index ist eher klassisch. Er erstellt eine sortierte Struktur, mit der du schnell nach bestimmten Werten suchen kannst. Bei JSONB kannst du BTREE verwenden, wenn du nach einer exakten Übereinstimmung suchst oder wenn du einen festen Schlüssel hast (zum Beispiel, wenn du den Wert des gesamten JSONB-Objekts vergleichen willst).
Wenn deine Spalte JSONB-Objekte wie diese enthält:
{"name": "Bob", "age": 30}
Der BTREE-Index ist nützlich, wenn du Einträge suchst, bei denen das ganze Objekt exakt gleich ist.
{"name": "Bob", "age": 30}
Erstellen eines Index für JSONB
Schauen wir uns zuerst an, wie man einen GIN-Index erstellt. Alles, was du brauchst, ist der magische Befehl CREATE INDEX. So sieht das aus:
-- Erstelle einen GIN-Index für die JSONB-Spalte
CREATE INDEX idx_jsonb_data ON orders USING GIN (data);
Hierbei gilt:
idx_jsonb_data– Name des Index.orders– Name der Tabelle.data– Spalte mit denJSONB-Daten.
Nachdem du diesen Index erstellt hast, laufen Abfragen, die nach Schlüsseln oder Werten in JSONB suchen, viel schneller.
Nehmen wir an, wir haben eine Tabelle orders mit einer Spalte data, die JSONB enthält:
| id | data |
|---|---|
| 1 | {"status": "pending", "total": 100} |
| 2 | {"status": "delivered", "total": 200} |
Abfrage ohne Index:
-- Finde alle Bestellungen mit Status "delivered"
SELECT * FROM orders WHERE data @> '{"status": "delivered"}';
Wenn die Tabelle groß ist, kann diese Abfrage lange dauern. Mit dem GIN-Index läuft sie aber deutlich schneller.
Wie man einen BTREE-Index erstellt
Um einen BTREE-Index zu erstellen, musst du ein bisschen anders vorgehen. Meistens musst du, um BTREE mit JSONB zu nutzen, angeben, dass du nicht das ganze Objekt, sondern einen Teil davon indexieren willst. Hier ein Beispiel:
-- Erstelle einen BTREE-Index für einen bestimmten Schlüssel
CREATE INDEX idx_jsonb_total ON orders ((data->>'total'));
Achte auf (data->>'total'). Das extrahiert den Wert des Schlüssels total aus dem JSONB-Objekt, und genau dieser Wert wird indexiert. Wenn du jetzt nach Bestellungen suchst, bei denen total = 100, nutzt PostgreSQL diesen Index.
Hier ein Beispiel mit denselben Daten:
| id | data |
|---|---|
| 1 | {"status": "pending", "total": 100} |
| 2 | {"status": "delivered", "total": 200} |
Abfrage:
-- Finde alle Bestellungen, bei denen total = 100
SELECT * FROM orders WHERE data->>'total' = '100';
Mit dem BTREE-Index auf data->>'total' läuft diese Abfrage viel schneller.
Vergleich GIN vs. BTREE
| Eigenschaft | GIN | BTREE |
|---|---|---|
| Was wird indexiert? | Schlüssel und Werte innerhalb von JSONB | Bestimmter Pfad oder Wert |
| Bester Anwendungsfall | Suche nach Teilen des Objekts | Suche nach einem bestimmten Wert |
| Performance beim Erstellen | Langsamer | Schneller |
| Performance bei der Suche | Schneller bei komplexen Strukturen | Schneller bei festen Werten |
| Operator-Unterstützung | @>, ?, `? |
,?&` |
Wenn du komplexe JSONB-Strukturen hast und oft Operatoren wie @> oder ? verwendest, nimm GIN. Wenn du nach bestimmten Werten oder festen Schlüsseln suchst, ist BTREE vielleicht die bessere Wahl.
Fallen und typische Fehler bei der Indexierung von JSONB
Mit JSONB-Indexierung kannst du viel erreichen, aber es gibt ein paar Stolperfallen, auf die du achten solltest.
- Kein Index, wo einer nötig wäre. Wenn du oft JSONB-Daten in Filtern (
WHERE) verwendest, aber keinen Index hast, werden deine Abfragen langsam sein. - Zu viele Indizes. Wenn du für jeden möglichen JSONB-Schlüssel einen Index anlegst, werden Inserts und Updates langsamer.
- Falsche Wahl des Index-Typs. Wenn deine Abfragen komplex sind und Operatoren wie
@>oder?nutzen, du aber einenBTREE-Index erstellt hast, bringt das keinen Performance-Gewinn. - Zu wenig Wissen über Pfade. Wenn du ständig auf verschachtelte Werte zugreifst, aber keinen Index für den bestimmten Pfad (z.B.
data->>'some_key') hast, bleibt deine Abfrage trotzdem langsam.
Fazit: Wann welchen Index verwenden?
- Nutze
GIN, wenn du Arrays oder komplexe Objekte hast, bei denen oft nach Schlüsseln und Werten gesucht wird. - Nutze
BTREE, wenn du nach exakten Übereinstimmungen suchst oder oft auf bestimmte Schlüssel zugreifst.
GO TO FULL VERSION