Prawidłowe wyniki?
Po pierwsze: poprawność. Chcesz stworzyć szereg unikalnych elementów? Twoje obecne zapytanie tego nie robi. Funkcja uniq()
z modułu intarray obiecuje tylko:
usuń sąsiadujące duplikaty
Jak nakazuje to instrukcja , musisz:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Daje także posortowane tablice - zakładając, że tego chcesz, nie wyjaśniłeś.
Widzę, że masz sort()
skrzypce , więc może to być literówka w twoim pytaniu.
Postgres 9.5
Tak czy inaczej, spodoba ci się nowy Postgres 9.5 (obecnie beta). Zapewnia możliwości array_agg_mult()
gotowego i znacznie szybszego:
Wprowadzono również inne ulepszenia wydajności w zakresie obsługi tablicy.
Pytanie
Głównym celem array_agg_mult()
jest agregacja tablic wielowymiarowych, ale i tak powstają tablice 1-wymiarowe. Chciałbym więc przynajmniej spróbować tego alternatywnego zapytania:
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;
Co również dotyczy twojego pytania:
Czy funkcja agregująca może bezpośrednio usuwać duplikaty?
Tak, może DISTINCT
. Nie jest to jednak szybsze niż w uniq()
przypadku tablic całkowitoliczbowych, które zostały zoptymalizowane dla tablic całkowitoliczbowych, podczas gdy DISTINCT
jest ogólne dla wszystkich kwalifikujących się typów danych.
Nie wymaga intarray
modułu. Jednak wynik niekoniecznie jest posortowany. Postgres używa różnych algorytmów dla DISTINCT
(IIRC), duże zestawy są zwykle mieszane, a następnie wynik nie jest sortowany, chyba że dodasz wyraźne ORDER BY
. Jeśli potrzebujesz posortowane tablice, to mógłby dodać ORDER BY
do łącznej funkcji bezpośrednio:
array_agg(DISTINCT elem ORDER BY elem)
Ale zwykle jest to wolniejsze niż podawanie wstępnie posortowanych danych array_agg()
(jeden duży sort w porównaniu z wieloma małymi). Więc posortowałbym podzapytanie, a następnie agregował:
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;
To był najszybszy wariant w moim pobieżnym teście na Postgres 9.4.
Fiddle SQL oparty na tym, który podałeś.
Indeks
Nie widzę tutaj dużego potencjału dla żadnego indeksu. Jedyną opcją byłoby:
CREATE INDEX ON right2 (t1, arr);
Ma to sens tylko wtedy, gdy uzyskuje się z tego skany tylko indeksowe - co stanie się, jeśli podstawowa tabela right2
jest znacznie szersza niż tylko te dwie kolumny, a twoja konfiguracja kwalifikuje się do skanów tylko indeksowych. Szczegóły na Wiki Postgres.
right2.arr
mieć wartość NULL, jak sugeruje schemat demonstracyjny? Czy potrzebujesz wynikowo posortowanych tablic?