Bij het ophalen van alle of de meeste rijen uit een tabel, is de snelste manier voor dit type zoekopdracht meestal om eerst te aggregeren / ondubbelzinnig maken. en doe later mee :
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;
Hoe meer rijen in meta
per rij in products
, hoe groter de impact op de prestaties.
Natuurlijk wil je een ORDER BY
. toevoegen clausule in de subquery definiëren welke rij om uit elke set in de subquery te kiezen. @Craig en @Clodoaldo hebben je daar al over verteld. Ik retourneer de meta
rij met de hoogste id
.
SQL Fiddle.
Details voor DISTINCT ON
:
- Selecteer de eerste rij in elke GROUP BY-groep?
Prestaties optimaliseren
Toch is dit niet altijd de snelste oplossing. Afhankelijk van de gegevensdistributie zijn er verschillende andere zoekstijlen. Voor dit simpele geval met een andere join, liep deze aanzienlijk sneller in een test met grote tafels:
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;
Als u de niet-beschrijvende id
. niet zou gebruiken als kolomnamen zouden we geen naamconflicten tegenkomen en konden we gewoon SELECT p.*, m.*
schrijven . (Ik nooit gebruik id
als kolomnaam.)
Als prestaties uw belangrijkste vereiste zijn, overweeg dan meer opties:
- een
MATERIALIZED VIEW
met vooraf geaggregeerde gegevens vanmeta
, als uw gegevens niet (veel) veranderen. - een recursieve CTE die een losse index-scan emuleert voor een grote
meta
tafel met veel rijen per product (relatief weinig verschillendeproduct_id
).
Dit is de enige manier die ik ken om een index te gebruiken voor een DISTINCT-query over de hele tabel.