Resultados corretos?
Primeiro: correção. Deseja produzir uma matriz de elementos únicos? Sua consulta atual não faz isso. A função uniq()
do módulo intarray promete apenas:
remover duplicatas adjacentes
Como instruído no manual , você precisaria de:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Também fornece matrizes ordenadas - supondo que você queira isso, você não esclareceu.
Vejo que você tem sort()
no seu violino , então isso pode ser apenas um erro de digitação na sua pergunta.
Postgres 9.5
De qualquer forma, você vai adorar o novo Postgres 9.5 (atualmente beta). Ele fornece os recursos prontos array_agg_mult()
para uso e muito mais rápido:
Também houve outras melhorias de desempenho para manipulação de array.
Inquerir
O principal objetivo de array_agg_mult()
é agregar matrizes multidimensionais, mas você produz apenas matrizes unidimensionais de qualquer maneira. Então, pelo menos, tentaria esta consulta alternativa:
SELECT l.d + r.d AS d_sum, array_agg(DISTINCT elem) AS result_arr
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
GROUP BY 1
ORDER BY 1;
O que também aborda sua pergunta:
A função agregada pode remover duplicatas diretamente?
Sim, pode, com DISTINCT
. Mas isso não é mais rápido do que uniq()
para matrizes inteiras, que foi otimizado para matrizes inteiras, enquanto DISTINCT
é genérico para todos os tipos de dados qualificados.
Não requer o intarray
módulo. No entanto , o resultado não é necessariamente classificado. O Postgres usa algoritmos variados para DISTINCT
(IIRC), grandes conjuntos geralmente são divididos em hash e o resultado não é classificado, a menos que você adicione explícito ORDER BY
. Se você precisar de matrizes classificadas, poderá adicionar ORDER BY
diretamente à função agregada:
array_agg(DISTINCT elem ORDER BY elem)
Mas isso normalmente é mais lento do que a alimentação de dados pré-classificados array_agg()
(uma grande classificação versus muitas pequenas). Então, eu classificaria em uma subconsulta e depois agregaria:
SELECT d_sum, uniq(array_agg(elem)) AS result_arr
FROM (
SELECT l.d + r.d AS d_sum, elem
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
ORDER BY 1, 2
) sub
GROUP BY 1
ORDER BY 1;
Essa foi a variante mais rápida no meu teste superficial no Postgres 9.4.
SQL Fiddle com base no que você forneceu.
Índice
Não vejo muito potencial para nenhum índice aqui. A única opção seria:
CREATE INDEX ON right2 (t1, arr);
Só faz sentido se você conseguir verificações apenas de índice - o que acontecerá se a tabela subjacente right2
for substancialmente mais ampla do que apenas essas duas colunas e sua instalação se qualificar para verificações apenas de índice. Detalhes no Wiki do Postgres.
right2.arr
ser NULL como sugere seu esquema demo? Você precisa de matrizes classificadas como resultado?