jsonb in Postgres 9.4+
Mit dem neuen binären JSON-Datentyp jsonbführte Postgres 9.4 stark verbesserte Indexoptionen ein . Sie können jetzt jsonbdirekt einen GIN-Index für ein Array erstellen:
CREATE TABLE tracks (id serial, artists jsonb);
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Zum Konvertieren des Arrays ist keine Funktion erforderlich. Dies würde eine Abfrage unterstützen:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>Dies ist der neue jsonbOperator "enthält" , der den GIN-Index verwenden kann. (Nicht für den Typ json, nur jsonb!)
Oder Sie verwenden die speziellere, nicht standardmäßige GIN-Operatorklasse jsonb_path_opsfür den Index:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops);
Gleiche Abfrage.
jsonb_path_opsUnterstützt derzeit nur den @>Operator. Aber es ist normalerweise viel kleiner und schneller. Es gibt weitere Indexoptionen, Details im Handbuch .
Wenn artists nur Namen enthalten sind, wie im Beispiel gezeigt, wäre es effizienter, zunächst einen weniger redundanten JSON-Wert zu speichern: Nur die Werte als Textprimitive und der redundante Schlüssel können im Spaltennamen enthalten sein.
Beachten Sie den Unterschied zwischen JSON-Objekten und primitiven Typen:
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 die Objektwerte , nur Schlüssel und Array - Elemente .
Oder (effizienter, wenn Namen häufig wiederholt werden):
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Abfrage:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
json in Postgres 9.3+
Dies sollte mit einer IMMUTABLE Funktion funktionieren :
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 Funktionsindex :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Und verwenden Sie eine solche Abfrage . Der Ausdruck in der WHEREKlausel muss mit dem im Index übereinstimmen:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Aktualisiert mit Feedback in Kommentaren. Wir müssen Array-Operatoren verwenden , um den GIN-Index zu unterstützen.
Der Operator "ist enthalten von" ist<@ in diesem Fall.
Hinweise zur Funktionsvolatilität
Sie können Ihre Funktion IMMUTABLEauch dann deklarieren , wenn dies json_array_elements() nicht der Fall ist.
Die meisten JSONFunktionen waren früher nur STABLE, nicht IMMUTABLE. Es gab eine Diskussion auf der Hackerliste, um das zu ändern. Die meisten sind IMMUTABLEjetzt. Ü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%';
Funktionsindizes funktionieren nur mit IMMUTABLEFunktionen.