Richtige Ergebnisse?
Zunächst einmal: Korrektheit. Sie möchten eine Reihe einzigartiger Elemente erstellen? Ihre aktuelle Abfrage macht das nicht. Die Funktion uniq()
des Intarray- Moduls verspricht nur:
benachbarte Duplikate entfernen
Wie im Handbuch beschrieben , benötigen Sie:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Gibt Ihnen auch sortierte Arrays - vorausgesetzt, Sie möchten das, haben Sie nicht geklärt.
Ich sehe, Sie haben sort()
in Ihrer Geige , also kann dies nur ein Tippfehler in Ihrer Frage sein.
Postgres 9.5
In jedem Fall werden Sie den neuen Postgres 9.5 (derzeit Beta) lieben . Es bietet die Funktionen von array_agg_mult()
sofort einsatzbereit und viel schneller:
Es gab auch andere Leistungsverbesserungen für die Array-Handhabung.
Abfrage
Der Hauptzweck von array_agg_mult()
besteht darin, mehrdimensionale Arrays zu aggregieren, aber Sie erzeugen sowieso nur eindimensionale Arrays. Also würde ich zumindest diese alternative Abfrage versuchen:
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;
Welches auch Ihre Frage anspricht:
Kann die Aggregatfunktion Duplikate direkt entfernen?
Ja, das kann es mit DISTINCT
. Dies ist jedoch nicht schneller als uniq()
bei Integer-Arrays, die für Integer-Arrays optimiert wurden, während sie DISTINCT
für alle qualifizierenden Datentypen generisch sind.
Benötigt das intarray
Modul nicht. Das Ergebnis ist jedoch nicht unbedingt sortiert. Postgres verwendet unterschiedliche Algorithmen für DISTINCT
(IIRC). Große Mengen werden normalerweise gehasht. Das Ergebnis wird nur sortiert, wenn Sie explizit hinzufügen ORDER BY
. Wenn Sie sortierten Arrays benötigen, Sie könnten hinzufügen , ORDER BY
direkt auf die Aggregatfunktion:
array_agg(DISTINCT elem ORDER BY elem)
Dies ist jedoch in der Regel langsamer als das Zuführen vorsortierter Daten array_agg()
(eine große Sortierung gegenüber vielen kleinen Sortierungen). Also würde ich in einer Unterabfrage sortieren und dann aggregieren:
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;
Dies war die schnellste Variante in meinem flüchtigen Test auf Postgres 9.4.
SQL Fiddle basierend auf dem von Ihnen angegebenen.
Index
Ich sehe hier nicht viel Potenzial für einen Index. Die einzige Option wäre:
CREATE INDEX ON right2 (t1, arr);
Dies ist nur dann sinnvoll, wenn Sie nur Index-Scans erhalten. Dies ist der Fall, wenn die zugrunde liegende Tabelle right2
wesentlich breiter als nur diese beiden Spalten ist und Ihr Setup für Nur-Index-Scans qualifiziert ist. Details im Postgres Wiki.
right2.arr
NULL sein, wie es Ihr Demo-Schema vorschlägt? Benötigen Sie als Ergebnis sortierte Arrays?