PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

GROUP oder DISTINCT nach JOIN gibt Duplikate zurück

Beim Abrufen aller oder der meisten Zeilen aus einer Tabelle besteht der schnellste Weg für diese Art von Abfrage normalerweise darin, zuerst zu aggregieren / zu disambiguieren und trete später bei :

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;

Je mehr Zeilen in meta pro Zeile in products , desto größer ist die Auswirkung auf die Leistung.

Natürlich möchten Sie einen ORDER BY hinzufügen -Klausel in der Unterabfrage definieren welche Zeile, die aus jedem Satz in der Unterabfrage auszuwählen ist. @Craig und @Clodoaldo haben dir bereits davon erzählt. Ich gebe das meta zurück Zeile mit der höchsten id .

SQL-Geige.

Details für DISTINCT ON :

  • Erste Zeile in jeder GROUP BY-Gruppe auswählen?

Leistung optimieren

Allerdings ist dies nicht immer die schnellste Lösung. Je nach Datenverteilung gibt es verschiedene andere Abfragestile. Für diesen einfachen Fall mit einem anderen Join lief dieser in einem Test mit großen Tabellen erheblich schneller:

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;

Wenn Sie nicht die nicht beschreibende id verwenden würden als Spaltennamen würden wir nicht auf Namenskollisionen stoßen und könnten einfach SELECT p.*, m.* schreiben . (Ich nie Verwenden Sie id als Spaltenname.)

Wenn Leistung Ihre höchste Anforderung ist, ziehen Sie weitere Optionen in Betracht:

  • eine MATERIALIZED VIEW mit voraggregierten Daten aus meta , wenn sich Ihre Daten nicht (viel) ändern.
  • ein rekursiver CTE, der einen losen Index-Scan emuliert für ein großes meta Tabelle mit vielen Zeilen pro Produkt (relativ wenige eindeutige product_id ).
    Dies ist die einzige Möglichkeit, die ich kenne, um einen Index für eine DISTINCT-Abfrage über die gesamte Tabelle zu verwenden.