У меня есть две таблицы, left2
и right2
. Обе таблицы будут большими (1-10 миллионов строк).
CREATE TABLE left2(id INTEGER, t1 INTEGER, d INTEGER);
ALTER TABLE left2 ADD PRIMARY KEY (id,t1);
CREATE TABLE right2( t1 INTEGER, d INTEGER, arr INTEGER[] );
ALTER TABLE right2 ADD PRIMARY KEY(t1,d);
Я выполню этот тип запроса:
SELECT l.d + r.d,
UNIQ(SORT((array_agg_mult(r.arr)))
FROM left2 l,
right2 r
WHERE l.t1 = r.t1
GROUP BY l.d + r.d
ORDER BY l.d + r.d;
Где для агрегации массивов я использую функцию:
CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC=array_cat,
STYPE=anyarray,
INITCOND='{}');
После объединения массивов я использую UNIQ
функцию intarray
модуля. Есть ли более эффективный способ сделать это? Есть ли на arr
поле какой-либо индекс для ускорения слияния (с удалением дубликатов)? Может ли агрегатная функция удалять дубликаты напрямую? Оригинальные массивы можно считать отсортированными (и они уникальны), если это помогает.
Скрипка SQL здесь :
postgresql
postgresql-9.3
aggregate
array
Александрос
источник
источник
right2.arr
быть NULL, как предполагает ваша демонстрационная схема? Вам нужны отсортированные массивы в результате?Ответы:
Правильные результаты?
Прежде всего: правильность. Вы хотите создать массив уникальных элементов? Ваш текущий запрос не делает этого. Функция
uniq()
из модуля intarray обещает только:Как указано в руководстве , вам потребуется:
Также дает вам отсортированные массивы - предполагая, что вы хотите, вы не уточнили.
Я вижу , у вас есть
sort()
в вашей скрипке , так что это может быть просто опечатка в вашем вопросе.Postgres 9,5
В любом случае, вам понравится новый Postgres 9.5 (в настоящее время бета). Это обеспечивает возможности
array_agg_mult()
из коробки и намного быстрее:Также были другие улучшения производительности для обработки массива.
запрос
Основная цель
array_agg_mult()
состоит в агрегировании многомерных массивов, но в любом случае вы производите только одномерные массивы. Так что я бы хотя бы попробовал этот альтернативный запрос:Который также отвечает на ваш вопрос:
Да, может, с
DISTINCT
. Но это не быстрее, чемuniq()
для целочисленных массивов, которые были оптимизированы для целочисленных массивов, и в то же времяDISTINCT
являются общими для всех подходящих типов данных.Не требует
intarray
модуля. Однако результат не обязательно отсортирован. Postgres использует различные алгоритмы дляDISTINCT
(IIRC), большие наборы обычно хэшируются, тогда результат не сортируется, если вы не добавите явноеORDER BY
. Если вам нужны отсортированные массивы, вы можете добавитьORDER BY
к агрегатной функции напрямую:Но это обычно медленнее, чем подача предварительно отсортированных данных
array_agg()
(одна большая сортировка против множества мелких сортировок). Поэтому я бы отсортировал подзапрос, а затем агрегировал:Это был самый быстрый вариант в моем беглом тесте на Postgres 9.4.
SQL Fiddle на основе того, который вы предоставили.
Индекс
Я не вижу большого потенциала для какого-либо индекса здесь. Единственный вариант будет:
Это имеет смысл только в том случае, если вы получаете из этого только сканирование по индексу - что произойдет, если базовая таблица
right2
будет значительно шире, чем только эти два столбца, и ваша установка будет соответствовать сканированию только по индексу. Подробности в Postgres Wiki.источник
Я очень разочарован, это легко сделать в Microsoft Access. Вы можете создать запрос «удалить дубликаты», а затем посмотреть на SQL, чтобы увидеть, как он это делает. Мне придется запустить машину Windows, чтобы посмотреть. Они различаются, мастер запросов делает это.
Я думаю, что работает одна вещь - загрузить все ваши данные в одну таблицу, а затем выполнить SELECT DISTINCT в новой таблице. Вы также можете придерживаться порядка по пункту, пока вы на нем. Я сделал это как-то год назад, это должно быть.
Я объединяю данные о температуре за 2 года, датчик отправляет 2 копии одной и той же точки данных каждую минуту в качестве избыточной защиты. Иногда его разбивают, но я хочу оставить его. У меня также есть совпадения между файлами.
Если данные в течение всего цикла имеют одинаковый формат, на Unix-машине вы можете сделать что-то вроде
Но uniq сравнивает строки как строки и, например, 18.7000 отличается от 18.7. Я изменил свое программное обеспечение в течение 2 лет, поэтому у меня есть оба формата.
источник