Окончательная версия после комментариев ниже:
@ Дейв хочет latest price
за виджет. Вы можете сделать это в подзапросах и LIMIT 1
на виджет, но в современном PostgreSQL оконная функция делает работу более элегантно. Рассмотрим first_value()
/ last_value()
:
SELECT w.*
, first_value(p.price) OVER (PARTITION BY w.id
ORDER BY created_at DESC) AS latest_price
FROM (
SELECT *
FROM widgets
ORDER BY created_at DESC
LIMIT 20
) w
JOIN prices p ON p.widget_id = w.id
GROUP BY w.col1, w.col2 -- spell out all columns of w.*
Оригинальный пост по максимальной цене за виджет:
SELECT w.*
, max(p.price) AS max_price
FROM (
SELECT *
FROM widgets
ORDER BY created_at DESC
LIMIT 20
) w
JOIN prices p ON p.widget_id = w.id
GROUP BY w.col1, w.col2 -- spell out all columns of w.*
Исправление псевдонимов таблицы.
Получить все столбцы widgets
, как показывает вопрос
В PostgreSQL 8.3 вы должны указать все неагрегированные столбцы списка SELECT
в предложении GROUP BY
. В PostgreSQL 9.1 или новее столбец первичного ключа будет покрывать всю таблицу. Я цитирую руководство здесь :
Разрешить не-GROUP BY столбцы в списке целей запроса, когда основной
ключ указан в предложении GROUP BY
Я советую никогда не использовать идентификаторы смешанного регистра как maxWidgetPrice
. По умолчанию в PostgreSQL идентификаторы без кавычек свернуты в нижний регистр. Сделайте себе одолжение и используйте исключительно строчные идентификаторы.
Всегда используйте явные условия JOIN, где это возможно. Это канонический способ SQL, и он более читабелен.
OFFSET 0
просто шум
Индексы:
Однако ключом к производительности являются правильные индексы . Я бы пошел два индекса, как эти:
CREATE INDEX widgets_created_at_idx ON widgets (created_at DESC);
CREATE INDEX prices_widget_id_idx ON prices(widget_id, price DESC);
Второй - это многоколонный индекс , который должен обеспечить максимальную производительность для получения максимального выигрыша после определения 20 лучших виджетов с использованием первого индекса. Не уверен, что PostgreSQL 8.3 (по умолчанию для совместно используемой базы данных Heroku) уже достаточно умен, чтобы максимально использовать его. PostgreSQL 9.1, безусловно, есть.
Для последней цены (см. Комментарии) используйте этот индекс вместо:
CREATE INDEX prices_widget_id_idx ON prices(widget_id, created_at DESC);
Вы не должны (и не должны) просто доверять мне. Проверьте производительность и создайте планы запросов с помощью EXPLAIN ANALYZE с индексами и без них и убедитесь сами. Создание индекса должно быть очень быстрым, даже для миллиона строк.
Если вы решите перейти на автономную базу данных PostgreSQL на Heroku, вас может заинтересовать это недавнее сообщение в блоге Heroku :
- По умолчанию сейчас используется PostgreSQL 9.1.
- Теперь вы можете отменить длительные запросы.