Докато се извличат всички или повечето редове от таблица, най-бързият начин за този тип заявка обикновено е да се обобщи/определи първото и се присъединете по-късно :
SELECT *
FROM products p
JOIN (
SELECT DISTINCT ON (product_id) *
FROM meta
ORDER BY product_id, id DESC
) m ON m.product_id = p.id;
Колкото повече редове в meta
на ред в products
, толкова по-голямо е влиянието върху производителността.
Разбира се, ще искате да добавите ORDER BY
клаузата в подзаявката дефинира коя ред, за да изберете от всеки набор в подзаявката. @Craig и @Clodoaldo вече ви казаха за това. Връщам meta
ред с най-висок id
.
SQL Fiddle.
Подробности за DISTINCT ON
:
- Изберете ли първия ред във всяка група GROUP BY?
Оптимизиране на производителността
Все пак това не винаги е най-бързото решение. В зависимост от разпределението на данните има различни други стилове на заявки. За този прост случай, включващ друго присъединяване, този работи значително по-бързо в тест с големи таблици:
SELECT p.*, sub.meta_id, m.product_id, m.price, m.flag
FROM (
SELECT product_id, max(id) AS meta_id
FROM meta
GROUP BY 1
) sub
JOIN meta m ON m.id = sub.meta_id
JOIN products p ON p.id = sub.product_id;
Ако не бихте използвали неописателния id
като имена на колони, няма да се сблъскаме с колизии на именуване и бихме могли просто да напишем SELECT p.*, m.*
. (Аз никога използвайте id
като име на колона.)
Ако производителността е вашето първостепенно изискване, помислете за повече опции:
- a
MATERIALIZED VIEW
с предварително обобщени данни отmeta
, ако данните ви не се променят (много). - рекурсивен CTE, емулиращо разхлабено сканиране на индекс за голям
meta
таблица с много редове на продукт (сравнително малко различниproduct_id
).
Това е единственият начин, който знам да използвам индекс за DISTINCT заявка върху цялата таблица.