Sim, o operador de sobreposição
&&
poderia usar um índice GIN em arrays
. Muito útil para consultas esta para encontrar linhas com uma determinada pessoa (1
) entre uma série de atores:SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
No entanto , a lógica da sua consulta é inversa, procurando por todas as pessoas listadas nos arrays em
eg_assoc
. Um índice GIN é não ajuda aqui. Só precisamos do índice btree do PK person.id
. Consultas adequadas
Fundamentos:
As consultas a seguir preservam as matrizes originais exatamente como fornecidas , incluindo possíveis elementos duplicados e ordem original dos elementos. Funciona para matrizes unidimensionais . Dimensões adicionais são dobradas em uma única dimensão. É mais complexo preservar várias dimensões (mas totalmente possível):
WITH ORDINALITY
no Postgres 9.4 ou posterior
SELECT aid, actors
, ARRAY(SELECT name
FROM unnest(e.actors) WITH ORDINALITY a(id, i)
JOIN eg_person p USING (id)
ORDER BY a.i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM unnest(e.benefactors) WITH ORDINALITY b(id, i)
JOIN eg_person USING (id)
ORDER BY b.i) AS ben_names
FROM eg_assoc e;
LATERAL
consultas
Para PostgreSQL 9.3+ .
SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM eg_assoc e
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i)
) a(act_names)
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i)
) b(ben_names);
db<>fiddle aqui com algumas variantes.
Antigo sqlfiddle
Detalhe sutil:se uma pessoa não for encontrada, ela é simplesmente descartada. Ambas as consultas geram um matriz vazia (
'{}'
) se nenhuma pessoa for encontrada para toda a matriz. Outros estilos de consulta retornariam NULL
. Eu adicionei variantes ao violino. Subconsultas correlacionadas
Para Postgres 8.4+ (onde
generate_subsrcipts()
foi introduzido):SELECT aid, actors
, ARRAY(SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i) AS ben_names
FROM eg_assoc e;
Ainda pode ter melhor desempenho, mesmo no Postgres 9.3.
O
ARRAY
construtor
é mais rápido que array_agg()
. Ver:Sua consulta falhou
A consulta fornecida por @a_horse parece para fazer o trabalho, mas não é confiável, enganoso, potencialmente incorreto e desnecessariamente caro.
-
Junção cruzada de proxy devido a duas junções não relacionadas. Um anti-padrão sorrateiro. Ver:
Corrigido superficialmente comDISTINCT
emarray_agg()
to elimina as duplicatas geradas, mas isso é realmente colocar batom em um porco. Também elimina duplicatas no original porque é impossível dizer a diferença neste momento - o que é potencialmente incorreto.
-
A expressãoa_person.id = any(eg_assoc.actors)
funciona , mas elimina duplicatas do resultado (acontece duas vezes nesta consulta), que está errado, a menos que especificado.
-
A ordem original dos elementos da matriz não foi preservada . Isso é complicado em geral. Mas é agravado nesta consulta, porque os atores e benfeitores são multiplicados e tornados distintos novamente, o que garantia ordem arbitrária.
-
Nenhum alias de coluna noSELECT
externo resultar em nomes de colunas duplicados, o que faz com que alguns clientes falhem (não funcionam no violino sem aliases).
-
min(actors)
emin(benefactors)
são inúteis. Normalmente, basta adicionar as colunas aGROUP BY
em vez de agregá-los falsamente. Maseg_assoc.aid
é a coluna PK de qualquer maneira (cobrindo toda a tabela emGROUP BY
), então isso nem é necessário. Apenasactors, benefactors
.
Agregar todo o resultado é perda de tempo e esforço para começar. Use uma consulta mais inteligente que não multiplique as linhas de base, para que você não precise agregá-las novamente.