jsonb in Postgres 9.4+
Der binäre JSON-Datentyp jsonb verbessert die Indexoptionen erheblich. Sie können jetzt einen GIN-Index auf einem jsonb haben Array direkt:
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Es ist keine Funktion zum Konvertieren des Arrays erforderlich. Dies würde eine Abfrage unterstützen:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@> der jsonb ist "enthält"-Operator, der den GIN-Index verwenden kann. (Nicht für json , nur jsonb !)
Oder Sie verwenden die speziellere, nicht standardmäßige GIN-Operatorklasse jsonb_path_ops für den Index:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Gleiche Abfrage.
Derzeit jsonb_path_ops unterstützt nur den @> Operator. Aber es ist normalerweise viel kleiner und schneller. Es gibt weitere Indexoptionen, Details im Handbuch .
Wenn die Spalte artists nur Namen enthält, wie im Beispiel angezeigt, wäre es effizienter, nur die Werte zu speichern als JSON-Text Primitive und der redundante Schlüssel kann der Spaltenname sein.
Beachten Sie den Unterschied zwischen JSON-Objekten und primitiven Typen:
- Verwenden von Indizes in einem json-Array in PostgreSQL
CREATE TABLE tracks (id serial, artistnames jsonb);
INSERT INTO tracks VALUES (2, '["The Dirty Heads", "Louis Richards"]');
CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames); Abfrage:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
? funktioniert nicht für Objektwerte , nur Schlüssel und Array-Elemente .
Oder:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Abfrage:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Effizienter, wenn Namen stark dupliziert werden.
json in Postgres 9.3+
Dies sollte mit einem IMMUTABLE funktionieren Funktion :
CREATE OR REPLACE FUNCTION json2arr(_j json, _key text)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT elem->>_key FROM json_array_elements(_j) elem)';
Erstellen Sie diesen funktionalen Index :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Und verwenden Sie eine Abfrage so was. Der Ausdruck im WHERE -Klausel muss mit der im Index übereinstimmen:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Aktualisiert mit Feedback in den Kommentaren. Wir müssen Array-Operatoren verwenden um den GIN-Index zu unterstützen.
Der "ist enthalten in"-Operator <@ in diesem Fall.
Hinweise zur Funktionsvolatilität
Sie können Ihre Funktion IMMUTABLE deklarieren auch wenn json_array_elements() ist nicht war nicht.
Die meisten JSON Funktionen waren früher nur STABLE , nicht IMMUTABLE . Es gab eine Diskussion auf der Hackerliste, um das zu ändern. Die meisten sind IMMUTABLE jetzt. Überprüfen Sie mit:
SELECT p.proname, p.provolatile
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = 'pg_catalog'
AND p.proname ~~* '%json%';
Funktionale Indizes funktionieren nur mit IMMUTABLE Funktionen.