Des résultats corrects?
Tout d'abord: l'exactitude. Vous souhaitez produire un tableau d'éléments uniques? Votre requête actuelle ne fait pas cela. La fonction uniq()
du module intarray ne promet que:
supprimer les doublons adjacents
Comme indiqué dans le manuel , vous aurez besoin de:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Vous donne également des tableaux triés - en supposant que vous le vouliez, vous n'avez pas clarifié.
Je vois que vous avez sort()
dans votre violon , donc ce n'est peut-être qu'une faute de frappe dans votre question.
Postgres 9.5
Quoi qu'il en soit, vous allez adorer le nouveau Postgres 9.5 (actuellement en version bêta). Il offre les capacités prêtes array_agg_mult()
à l'emploi et beaucoup plus rapides:
Il y a également eu d'autres améliorations de performances pour la gestion des baies.
Requete
L'objectif principal de array_agg_mult()
est d'agréger des tableaux multidimensionnels, mais vous ne produisez de toute façon que des tableaux unidimensionnels. Je voudrais donc au moins essayer cette requête alternative:
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;
Ce qui répond également à votre question:
La fonction d'agrégation peut-elle supprimer directement les doublons?
Oui, c'est possible, avec DISTINCT
. Mais ce n'est pas plus rapide que uniq()
pour les tableaux entiers, qui a été optimisé pour les tableaux entiers, tandis qu'il DISTINCT
est générique pour tous les types de données éligibles.
Ne nécessite pas le intarray
module. Cependant , le résultat n'est pas nécessairement trié. Postgres utilise différents algorithmes pour DISTINCT
(IIRC), les grands ensembles sont généralement hachés, puis le résultat n'est pas trié sauf si vous ajoutez explicitement ORDER BY
. Si vous avez besoin de tableaux triés, vous pouvez ajouter ORDER BY
directement à la fonction d'agrégation:
array_agg(DISTINCT elem ORDER BY elem)
Mais c'est généralement plus lent que de fournir des données pré-triées array_agg()
(un grand tri par rapport à de nombreux petits tri). Je trierais donc dans une sous-requête, puis j'agrégerais:
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;
C'était la variante la plus rapide de mon test superficiel sur Postgres 9.4.
SQL Fiddle basé sur celui que vous avez fourni.
Indice
Je ne vois pas beaucoup de potentiel pour un indice ici. La seule option serait:
CREATE INDEX ON right2 (t1, arr);
Cela n'a de sens que si vous obtenez des analyses d'index uniquement - ce qui se produira si la table sous-jacente right2
est nettement plus large que ces deux colonnes et que votre configuration est qualifiée pour les analyses d'index uniquement. Détails dans le wiki Postgres.
right2.arr
être NULL comme le suggère votre schéma de démonstration? Avez-vous besoin de tableaux triés en conséquence?