jsonb
dans Postgres 9.4 et plus
Le type de données binaires JSON jsonb
améliore largement les options d'indexation. Il est désormais possible d'avoir un index GIN sur une jsonb
directement :
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Pas besoin d'une fonction pour convertir le tableau. Cela supporterait une requête :
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
étant le jsonb
opérateur "contient". qui peut utiliser l'indice GIN. (Pas pour json
seulement jsonb
!)
Ou vous utilisez la classe d'opérateurs GIN plus spécialisée, qui n'est pas la classe par défaut. jsonb_path_ops
pour l'index :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Même question.
Actuellement jsonb_path_ops
ne prend en charge que le @>
opérateur. Mais il est généralement beaucoup plus petit et plus rapide. Il y a plus d'options d'indexation, détails dans le manuel .
Si la colonne artists
ne retient que les noms tels qu'ils sont affichés dans l'exemple, il serait plus efficace de ne stocker que le nom de l'entreprise. valeurs en tant que texte JSON primitives et la redondance clé peut être le nom de la colonne.
Notez la différence entre les objets JSON et les types primitifs :
Une requête :
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
ne fonctionne pas pour l'objet valeurs juste clés y éléments du tableau .
Ou :
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Une requête :
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Plus efficace si les noms sont fortement dupliqués.
json
dans Postgres 9.3 et plus
Cela devrait fonctionner avec un IMMUTABLE
fonction :
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)';
Créez cette fonctionnel indice :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Et utilisez un requête comme ça. L'expression dans le WHERE
doit correspondre à celle de l'index :
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Mis à jour avec les réactions dans les commentaires. Nous devons utiliser opérateurs de tableau pour soutenir l'indice GIN.
Le site opérateur "est contenu par" <@
dans ce cas.
Notes sur la volatilité des fonctions
Vous pouvez déclarer votre fonction IMMUTABLE
même si json_array_elements()
n'est pas ne l'était pas.
Le plus JSON
Les fonctions n'étaient auparavant que STABLE
pas IMMUTABLE
. Il y a eu une discussion sur la liste des hackers pour changer cela. La plupart sont IMMUTABLE
maintenant. Vérifiez avec :
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%';
Les index fonctionnels ne fonctionnent qu'avec IMMUTABLE
fonctions.