Resultados correctos?
Primero: corrección. ¿Quieres producir una variedad de elementos únicos? Su consulta actual no hace eso. La función uniq()
del módulo intarray solo promete:
eliminar duplicados adyacentes
Como se indica en el manual , necesitaría:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
También le da arreglos ordenados , suponiendo que quiera eso, no lo aclaró.
Veo que tienes sort()
en tu violín , por lo que esto puede ser un error tipográfico en tu pregunta.
Postgres 9.5
De cualquier manera, te encantará el nuevo Postgres 9.5 (actualmente beta). Proporciona las capacidades array_agg_mult()
listas para usar y mucho más rápido:
También ha habido otras mejoras de rendimiento para el manejo de matrices.
Consulta
El propósito principal de array_agg_mult()
es agregar matrices multidimensionales, pero de todos modos solo se producen matrices unidimensionales. Entonces al menos probaría 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;
Lo que también aborda su pregunta:
¿Puede la función agregada eliminar duplicados directamente?
Sí, puede, con DISTINCT
. Pero eso no es más rápido que uniq()
para las matrices de enteros, que se ha optimizado para las matrices de enteros, mientras que DISTINCT
es genérico para todos los tipos de datos que califican.
No requiere el intarray
módulo. Sin embargo , el resultado no está necesariamente ordenado. Postgres utiliza algoritmos variables para DISTINCT
(IIRC), los conjuntos grandes generalmente se codifican, luego el resultado no se ordena a menos que agregue explícito ORDER BY
. Si necesita matrices ordenadas, puede agregar ORDER BY
directamente a la función de agregado:
array_agg(DISTINCT elem ORDER BY elem)
Pero eso suele ser más lento que alimentar datos previamente ordenados array_agg()
(un tipo grande versus muchos tipos pequeños). Entonces ordenaría una subconsulta y luego agregaría:
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;
Esta fue la variante más rápida en mi prueba superficial en Postgres 9.4.
SQL Fiddle basado en el que proporcionó.
Índice
No veo mucho potencial para ningún índice aquí. La única opción sería:
CREATE INDEX ON right2 (t1, arr);
Solo tiene sentido si obtiene escaneos de solo índice de esto, lo que sucederá si la tabla subyacente right2
es sustancialmente más ancha que solo estas dos columnas y su configuración califica para escaneos de solo índice. Detalles en el Wiki de Postgres.
right2.arr
ser NULL como sugiere su esquema de demostración? ¿Necesita arreglos ordenados como resultado?