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.