Mens du henter alle eller de fleste rækker fra en tabel, er den hurtigste måde for denne type forespørgsel typisk at aggregere / disambiguere først og deltag senere :
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;
Jo flere rækker i meta
række i products
, jo større indvirkning på ydeevnen.
Selvfølgelig skal du tilføje en ORDER BY
klausul i underforespørgslen definerer hvilken række for at vælge fra hvert sæt i underforespørgslen. @Craig og @Clodoaldo har allerede fortalt dig om det. Jeg returnerer meta
række med det højeste id
.
SQL Fiddle.
Detaljer for DISTINCT ON
:
- Vælg første række i hver GROUP BY-gruppe?
Optimer ydeevnen
Alligevel er dette ikke altid den hurtigste løsning. Afhængigt af datadistribution er der forskellige andre forespørgselsstile. For denne simple sag, der involverede en anden join, kørte denne betydeligt hurtigere i en test med store borde:
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;
Hvis du ikke ville bruge det ikke-beskrivende id
som kolonnenavne ville vi ikke støde på navnekollisioner og kunne simpelthen skrive SELECT p.*, m.*
. (Jeg aldrig brug id
som kolonnenavn.)
Hvis ydeevne er dit vigtigste krav, så overvej flere muligheder:
- en
MATERIALIZED VIEW
med forudaggregerede data frameta
, hvis dine data ikke ændrer sig (meget). - en rekursiv CTE, der emulerer en løs indeksscanning for en stor
meta
tabel med mange rækker pr. produkt (relativt få distinkteproduct_id
). ).
Dette er den eneste måde, jeg kender til at bruge et indeks til en DISTINCT-forespørgsel over hele tabellen.