Правильні результати?
Перш за все: правильність. Ви хочете створити масив унікальних елементів? Ваш поточний запит цього не робить. Функція uniq()
з модуля intarray обіцяє лише:
видалити сусідні дублікати
Як і інструкція в посібнику , вам знадобиться:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Також надає відсортовані масиви - припускаючи, що ви цього хочете, ви не уточнили.
Я бачу, що ви маєте sort()
свою загадку , тож це може бути просто помилка у вашому запитанні.
Постгрес 9.5
Так чи інакше, вам сподобається новий Postgres 9.5 (зараз бета-версія). Це забезпечує можливості array_agg_mult()
поза коробкою і набагато швидше:
Також було покращено продуктивність для обробки масиву.
Запит
Основна мета array_agg_mult()
- агрегувати багатовимірні масиви, але ви все одно створюєте лише одновимірні масиви. Тож я б принаймні спробував цей альтернативний запит:
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;
Що також стосується вашого питання:
Чи може функція сукупності видаляти дублікати безпосередньо?
Так, може, с DISTINCT
. Але це не швидше, ніж uniq()
для цілих масивів, оптимізованих для цілих масивів, в той час як DISTINCT
є загальним для всіх кваліфікованих типів даних.
Не потрібен intarray
модуль. Однак результат не обов'язково сортується. Postgres використовує різні алгоритми для DISTINCT
(IIRC), великі набори типово хешовані, тоді результат не сортується, якщо ви не додаєте явного ORDER BY
. Якщо вам потрібні відсортовані масиви, ви можете безпосередньо додати ORDER BY
до функції сукупності:
array_agg(DISTINCT elem ORDER BY elem)
Але це зазвичай повільніше, ніж подача попередньо відсортованих даних array_agg()
(один великий сорт проти багатьох малих сортів). Тож я б сортував підзапит і потім агрегував:
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;
Це був найшвидший варіант у моєму побіжному тесті на Postgres 9.4.
SQL Fiddle на основі тієї, яку ви надали.
Покажчик
Я не бачу тут великого потенціалу для будь-якого індексу. Єдиний варіант:
CREATE INDEX ON right2 (t1, arr);
Має сенс, лише якщо ви отримаєте сканування, що стосуються лише індексу, - це станеться, якщо нижня таблиця right2
істотно ширша, ніж лише ці два стовпці, і ваша установка може відповідати скануванню лише для індексів. Детальніше у Postgres Wiki.
right2.arr
бути NULL так, як пропонує ваша демо-схема? Вам потрібні відсортовані масиви як результат?