Podczas pobierania wszystkich lub większości wierszy z tabeli najszybszym sposobem dla tego typu zapytań jest zazwyczaj agregacja/ujednoznacznienie pierwszy i dołącz później :
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;
Więcej wierszy w meta
na wiersz w products
, tym większy wpływ na wydajność.
Oczywiście będziesz chciał dodać ORDER BY
klauzula w podzapytaniu definiuje które wiersz do wybrania z każdego zestawu w podzapytaniu. @Craig i @Clodoaldo już ci o tym powiedzieli. Zwracam meta
wiersz z najwyższym id
.
Skrzypce SQL.
Szczegóły dla DISTINCT ON
:
- Wybrać pierwszy wiersz w każdej grupie GROUP BY?
Optymalizuj wydajność
Jednak nie zawsze jest to najszybsze rozwiązanie. W zależności od dystrybucji danych istnieją różne inne style zapytań. W tym prostym przypadku z innym złączeniem, ten przebiegł znacznie szybciej w teście z dużymi tabelami:
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;
Jeśli nie użyjesz nieopisowego id
jako nazwy kolumn, nie napotkalibyśmy kolizji nazw i moglibyśmy po prostu napisać SELECT p.*, m.*
. (Ja nigdy użyj id
jako nazwę kolumny.)
Jeśli wydajność jest Twoim najważniejszym wymaganiem, rozważ więcej opcji:
MATERIALIZED VIEW
ze wstępnie zagregowanymi danymi zmeta
, jeśli Twoje dane się nie zmieniają (znacznie).- rekurencyjne CTE emulujące luźne skanowanie indeksu dla dużego
meta
stół z wieloma wierszy na produkt (stosunkowo kilka odrębnychproduct_id
).
To jedyny znany mi sposób na użycie indeksu dla zapytania DISTINCT dla całej tabeli.