PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Índice PostgreSQL em JSON


Seus outros dois índices não funcionarão simplesmente porque o ->> operador retorna text , enquanto você obviamente tem o jsonb classes de operadores de gin em mente. Observe que você menciona apenas json , mas na verdade você precisa de jsonb para recursos avançados de indexação.

Para elaborar a melhor estratégia de indexação, você teria que definir mais detalhadamente quais consultas cobrir. Você só está interessado em vacas? Ou todos os animais / todas as tags? Quais operadores são possíveis? Seu documento JSON também inclui chaves não animais? O que fazer com aqueles? Deseja incluir linhas no índice em que vacas (ou qualquer outra coisa) não apareçam no documento JSON?

Supondo:
  • Estamos interessados ​​apenas em vacas no primeiro nível de nidificação.
  • O valor é sempre um integer válido .
  • Não estamos interessados ​​em filas sem vacas.

Eu sugiro um índice btree funcional, bem como você já tem, mas converta o valor para integer . Acho que você não gostaria que a comparação fosse avaliada como text (onde '2' é maior que '1111').
CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int));  -- !

O conjunto extra de parênteses é necessário para que a abreviação de conversão torne a sintaxe da expressão de índice inequívoca.

Use a mesma expressão em suas consultas para fazer o Postgres perceber que o índice é aplicável:
SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3;

Se você precisar de um jsonb mais genérico índice, considere:
  • Qual ​​é o índice adequado para consultar estruturas em arrays no Postgres jsonb?

Para um conhecido, estático, trivial número de animais (como você comentou), sugiro índices parciais como:
CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int))
WHERE (animal ->> 'cow') IS NOT NULL;

CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int))
WHERE (animal ->> 'chicken') IS NOT NULL;

etc.

Talvez seja necessário adicionar a condição de índice à consulta:
SELECT * FROM farm
WHERE (animal ->> 'cow')::int > 3
AND   (animal ->> 'cow') IS NOT NULL; 

Pode parecer redundante, mas pode ser necessário. Teste com ANALYZE !