jsonb
en Postgres 9.4+
Con el nuevo tipo de datos JSON binario jsonb
, Postgres 9.4 introdujo opciones de índice ampliamente mejoradas . Ahora puede tener un índice GIN en una jsonb
matriz directamente:
CREATE TABLE tracks (id serial, artists jsonb);
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
No se necesita una función para convertir la matriz. Esto apoyaría una consulta:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
siendo el nuevo jsonb
operador "contiene" , que puede utilizar el índice GIN. (¡No para tipo json
, solo jsonb
!)
O usa la clase de operador GIN más especializada y no predeterminada jsonb_path_ops
para el índice:
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops);
Misma consulta.
Actualmente jsonb_path_ops
solo es compatible con el @>
operador. Pero normalmente es mucho más pequeño y rápido. Hay más opciones de índice, detalles en el manual .
Si artists
solo contiene nombres como se muestra en el ejemplo, sería más eficiente almacenar un valor JSON menos redundante para empezar: solo los valores como primitivas de texto y la clave redundante pueden estar en el nombre de la columna.
Tenga en cuenta la diferencia entre los objetos JSON y los tipos primitivos:
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);
Consulta:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
no funciona para valores de objeto , solo claves y elementos de matriz .
O (más eficiente si los nombres se repiten con frecuencia):
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Consulta:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
json
en Postgres 9.3+
Esto debería funcionar con una IMMUTABLE
función :
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)';
Cree este índice funcional :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
Y usa una consulta como esta. La expresión de la WHERE
cláusula debe coincidir con la del índice:
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Actualizado con retroalimentación en comentarios. Necesitamos usar operadores de matriz para admitir el índice GIN.
El operador "está contenido por"<@
en este caso.
Notas sobre la volatilidad de la función
Puede declarar su función IMMUTABLE
incluso si json_array_elements()
no lo fue.
La mayoría de las JSON
funciones solían ser únicas STABLE
, no IMMUTABLE
. Hubo una discusión en la lista de hackers para cambiar eso. La mayoría lo son IMMUTABLE
ahora. Comprueba con:
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%';
Los índices funcionales solo funcionan con IMMUTABLE
funciones.