Пересмотренный ответ после некоторого рассмотрения
SELECT *
FROM ta_price a
JOIN (
SELECT catalogproduct_id, max(timestamp) ts
FROM ta_price
GROUP BY catalogproduct_id
) b ON a.catalogproduct_id = b.catalogproduct_id
AND a.timestamp = b.ts
AND a.buy > a.sell;
buy
и sell
не квалифицированы в вашем вопросе.В зависимости от селективности buy > sell
вы можете ускорить запрос, добавив ту же самую фразу WHERE
в подвыбор.Однако это дает разные результаты .Я добавляю его на всякий случай, чтобы вы могли его пропустить:
SELECT *
FROM ta_price a
JOIN (
SELECT catalogproduct_id, max(timestamp) ts
FROM ta_price
WHERE buy > sell
GROUP BY catalogproduct_id
) b ON a.catalogproduct_id = b.catalogproduct_id
AND a.timestamp = b.ts
WHERE a.buy > a.sell;
В любом случае, простой индекс, такой как @Will, поможет:
CREATE INDEX my_idx ON ta_price (catalogproduct_id, отметка времени);
Однако существует более высокий подход.
Безусловный max()
в подвыборке приведет к последовательному сканированию таблицы независимо от индексов.Такая операция никогда не будет быстрой с 2,2 м строк.
Условие JOIN
в сочетании с предложением WHERE
внешнего SELECT
получит прибыль от индекса, подобного приведенному выше.В зависимости от селективности buy > sell
a частичный индекс будет немного или существенно быстрее и, соответственно, меньше на диске и в ОЗУ:
CREATE INDEX my_partial_idx ON ta_price (catalogproduct_id, timestamp)
WHERE buy > sell;
Порядок столбцов виндекс не имеет значения в этом случае.Это также ускорит мой второй вариант запроса.
Вы упомянули таблицу для "исторических" целей?Если это означает, что нет новых данных, вы могли бы значительно ускорить процесс с помощью материализованного представления .
С другой стороны: я бы не использовал timestamp
в качестве имени столбца.Это разрешено в PostgreSQL, но это зарезервированное слово во всех стандартах SQL.
ОК, первые вещи последние : для таблицы из 2,2 м строквам нужно намного больше ресурсов, чем есть в Postgres.
- Посмотрите на ваш файл postgresql.conf и проверьте настройки для
shared_buffers
и work_mem
для начала. - Обратитесь к postgres wiki для настройки производительности
- Обратитесь к руководству по штрафам по Расход ресурсов
- Обратитесь к руководству по штрафам по Расходам на планировщик
Увеличьте этинастройка статистики:
ALTER TABLE tmp.ta_price ALTER COLUMN buy SET STATISTICS 1000;<br>
ALTER TABLE tmp.ta_price ALTER COLUMN sell SET STATISTICS 1000;<br>
ALTER TABLE tmp.ta_price ALTER COLUMN ts SET STATISTICS 1000;
Затем запустите ANALYZE tmp.ta_price;
Убедитесь, что autovacuum работает.Если сомневаетесь, запустите VACUUM ANALYZE ta_price
и посмотрите, имел ли он эффект.
Я играл с тестовой настройкой wildplasser (, которая была очень полезной! ) на установке pg 8.4 с ограниченными ресурсами.Вот общее время выполнения с EXPLAIN ANYLYZE
Erwin 1) 901.487 ms
wildplasser 1) 1148.045 ms
A.H. 2922.113 ms
Вариант 2 с дополнительным предложением (покупка> продажа):
Erwin 2) 536.678 ms
wildplasser 2) 809.215 ms
С частичным индексом:
Erwin 1) 1166.793 ms -- slower (!), than unexpected
Вероятно, расходы на планировщик выключены, этот тестовый кластер базы данных оптимизирован для основной базы данных, которая имеет гораздо больше ресурсов.
wildplasser 1) 1122.609 ms -- rest is faster as expected
Erwin 2) 481.487 ms
wildplasser 2) 769.887 ms
Резюме
Версия AH занимает намного больше времени (тот же результат, о котором вы сообщали).Оконные функции имеют тенденцию быть медленными, особенно в старых версиях postgres.Мой альтернативный запрос в два раза быстрее, чем ожидалось.Вопрос в том, нужны ли разные результаты - может быть, нет.
В любом случае, это были 300 тыс. СтрокЗапрос занимает 0,5 - 1 с в версии 8.4 с ограниченными ресурсами (но в основном с правильными настройками) на 5-летнем сервере.С приличной машиной и приличными настройками (достаточно оперативной памяти!) Вы должны понизить ее до при 10 с как минимум.