PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

GROUP o DISTINCT dopo JOIN restituisce duplicati

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 da meta , 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 pochi product_id distinti ).
    Questo è l'unico modo che conosco per utilizzare un indice per una query DISTINCT sull'intera tabella.