jsonb
no Postgres 9.4+
O tipo de dados JSON binário
jsonb
melhora amplamente as opções de índice. Agora você pode ter um índice GIN em um jsonb
matriz diretamente:CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
Não há necessidade de uma função para converter a matriz. Isso suportaria uma consulta:
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
sendo o jsonb
operador "contém", que pode usar o índice GIN. (Não para json
, apenas jsonb
!) Ou você usa a classe de operador GIN mais especializada e não padrão
jsonb_path_ops
para o índice:CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
Mesma consulta.
Atualmente
jsonb_path_ops
suporta apenas o @>
operador. Mas normalmente é muito menor e mais rápido. Há mais opções de índice, detalhes no manual . Se a coluna
artists
contém apenas os nomes exibidos no exemplo, seria mais eficiente armazenar apenas os valores como texto JSON primitivos e a chave redundante pode ser o nome da coluna. Observe a diferença entre objetos JSON e tipos primitivos:
- Usando índices no array json no 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);
Inquerir:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
não funciona para objetos valores , apenas chaves e elementos de matriz . Ou:
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
Inquerir:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
Mais eficiente se os nomes forem altamente duplicados.
json
no Postgres 9.3+
Isso deve funcionar com um
IMMUTABLE
função :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)';
Crie este índice funcional :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
E use uma consulta assim. A expressão no
WHERE
A cláusula deve corresponder à do índice:SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
Atualizado com feedback nos comentários. Precisamos usar operadores de matriz para suportar o índice GIN.
O operador "está contido por"
<@
nesse caso. Notas sobre a volatilidade da função
Você pode declarar sua função
IMMUTABLE
mesmo se json_array_elements()
A maioria dos
JSON
funções costumavam ser apenas STABLE
, não IMMUTABLE
. Houve uma discussão na lista de hackers para mudar isso. A maioria é IMMUTABLE
agora. Verificar com: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%';
Índices funcionais só funcionam com
IMMUTABLE
funções.