jsonb
in Postgres 9.4+
Mit dem neuen binären JSON-Datentyp jsonb
führte Postgres 9.4 stark verbesserte Indexoptionen ein . Sie können jetzt jsonb
direkt 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 jsonb
Operator "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_ops
für den Index:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops);
Gleiche Abfrage.
jsonb_path_ops
Unterstü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 WHERE
Klausel 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 IMMUTABLE
auch dann deklarieren , wenn dies json_array_elements()
nicht der Fall ist.
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%';
Funktionsindizes funktionieren nur mit IMMUTABLE
Funktionen.