När du hämtar alla eller de flesta rader från en tabell, är det snabbaste sättet för den här typen av sökning vanligtvis att aggregera / disambiguera först och gå med senare :
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;
Ju fler rader i meta
per rad i products
, desto större påverkan på prestandan.
Naturligtvis vill du lägga till en ORDER BY
klausul i underfrågan definierar vilken rad för att välja formulär för varje uppsättning i underfrågan. @Craig och @Clodoaldo har redan berättat om det. Jag returnerar meta
rad med det högsta id
.
SQL Fiddle.
Detaljer för DISTINCT ON
:
- Välj första raden i varje GROUP BY-grupp?
Optimera prestanda
Ändå är detta inte alltid den snabbaste lösningen. Beroende på datadistribution finns det olika andra frågestilar. För det här enkla fallet som involverade en annan join, gick den här betydligt snabbare i ett test med stora tabeller:
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;
Om du inte skulle använda det icke-beskrivande id
som kolumnnamn skulle vi inte stöta på namnkollisioner och kunde helt enkelt skriva SELECT p.*, m.*
. (Jag aldrig använd id
som kolumnnamn.)
Om prestanda är ditt viktigaste krav, överväg fler alternativ:
- en
MATERIALIZED VIEW
med föraggregerade data frånmeta
, om dina uppgifter inte ändras (mycket). - en rekursiv CTE som emulerar en lös indexskanning för en stor
meta
tabell med många rader per produkt (relativt få distinktaproduct_id
). ).
Detta är det enda sättet jag vet att använda ett index för en DISTINCT-fråga över hela tabellen.