Durante il recupero di tutte o la maggior parte delle righe da una tabella, il modo più veloce per questo tipo di query in genere è aggregare/disambiguare prima e unisciti più tardi :
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;
Più righe in meta
per riga in products
, maggiore è l'impatto sulle prestazioni.
Ovviamente, ti consigliamo di aggiungere un ORDER BY
La clausola nella sottoquery definisce quale riga per selezionare da ogni set nella sottoquery. @Craig e @Clodoaldo te ne hanno già parlato. Sto restituendo il meta
riga con l'id
più alto .
SQL Violino.
Dettagli per DISTINCT ON
:
- Seleziona la prima riga in ogni gruppo GROUP BY?
Ottimizza le prestazioni
Tuttavia, questa non è sempre la soluzione più veloce. A seconda della distribuzione dei dati, esistono vari altri stili di query. Per questo semplice caso che coinvolge un altro join, questo è stato eseguito molto più velocemente in un test con grandi tabelle:
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;
Se non dovessi utilizzare il id
non descrittivo come nomi di colonna, non ci imbatteremmo in collisioni di nomi e potremmo semplicemente scrivere SELECT p.*, m.*
. (Io mai usa id
come nome della colonna.)
Se le prestazioni sono il tuo requisito fondamentale, considera più opzioni:
- a
MATERIALIZED VIEW
con dati preaggregati dameta
, se i tuoi dati non cambiano (molto). - un CTE ricorsivo che emula una scansione dell'indice allentata per un grande
meta
tabella con molti righe per prodotto (relativamente pochiproduct_id
distinti ).
Questo è l'unico modo che conosco per utilizzare un indice per una query DISTINCT sull'intera tabella.