Angenommen, ich habe eine Tabelle mit Kunden und eine Tabelle mit Einkäufen. Jeder Einkauf gehört einem Kunden. Ich möchte eine Liste aller Kunden zusammen mit ihrem letzten Einkauf in einer SELECT-Anweisung erhalten. Was ist die beste Vorgehensweise? Irgendwelche Ratschläge zum Erstellen von Indizes?
Bitte verwenden Sie diese Tabellen- / Spaltennamen in Ihrer Antwort:
- Kunde: ID, Name
- Kauf: ID, Kunden-ID, Artikel-ID, Datum
Und wäre es in komplizierteren Situationen (in Bezug auf die Leistung) vorteilhaft, die Datenbank zu denormalisieren, indem der letzte Kauf in die Kundentabelle aufgenommen wird?
Wenn die (Kauf-) ID garantiert nach Datum sortiert ist, können die Aussagen durch die Verwendung von etwas vereinfacht werden LIMIT 1
?
Antworten:
Dies ist ein Beispiel für das
greatest-n-per-group
Problem, das regelmäßig bei StackOverflow aufgetreten ist.So empfehle ich normalerweise, es zu lösen:
Erläuterung: Bei einer gegebenen Zeile
p1
sollte es keine Zeilep2
mit demselben Kunden und einem späteren Datum geben (oder bei Krawatten ein späteresid
). Wenn wir feststellen, dass dies zutrifft,p1
ist dies der letzte Kauf für diesen Kunden.In Bezug auf Indizes, würde ich eine Verbindung Index in erstellen
purchase
über die Spalten (customer_id
,date
,id
). Dies kann ermöglichen, dass die äußere Verbindung unter Verwendung eines Abdeckungsindex durchgeführt wird. Stellen Sie sicher, dass Sie auf Ihrer Plattform testen, da die Optimierung von der Implementierung abhängt. Verwenden Sie die Funktionen Ihres RDBMS, um den Optimierungsplan zu analysieren. ZBEXPLAIN
auf MySQL.Einige Leute verwenden Unterabfragen anstelle der oben gezeigten Lösung, aber ich finde, dass meine Lösung das Auflösen von Bindungen erleichtert.
quelle
Sie können dies auch mit einer Unterauswahl versuchen
Die Auswahl sollte allen Kunden und ihrem letzten Kaufdatum beitreten .
quelle
INNER JOIN
zu aLEFT OUTER JOIN
.purchase
Tabelle hätten, das Datum und die customer_id, aber die Abfrage fragt nach allen Feldern aus der Tabelle.Sie haben die Datenbank nicht angegeben. Wenn es sich um eine handelt, die analytische Funktionen ermöglicht, ist es möglicherweise schneller, diesen Ansatz zu verwenden als die GROUP BY-Methode (definitiv schneller in Oracle, höchstwahrscheinlich schneller in den späten SQL Server-Editionen, keine Kenntnis von anderen).
Die Syntax in SQL Server lautet:
quelle
Ein anderer Ansatz wäre, eine
NOT EXISTS
Bedingung in Ihrer Beitrittsbedingung zu verwenden, um auf spätere Einkäufe zu testen:quelle
AND NOT EXISTS
Teil in einfachen Worten erklären ?Ich habe diesen Thread als Lösung für mein Problem gefunden.
Aber als ich sie ausprobierte, war die Leistung gering. Unten ist mein Vorschlag für eine bessere Leistung.
Hoffe das wird hilfreich sein.
quelle
top 1
undordered it by
MaxDatedesc
Wenn Sie PostgreSQL verwenden, können
DISTINCT ON
Sie die erste Zeile in einer Gruppe suchen.PostgreSQL Docs - Distinct On
Beachten Sie, dass die
DISTINCT ON
Felder - hiercustomer_id
- mit den Feldern ganz links im Feld übereinstimmen müssenORDER BY
Klausel .Vorsichtsmaßnahme: Dies ist eine nicht standardmäßige Klausel.
quelle
Versuchen Sie dies, es wird helfen.
Ich habe dies in meinem Projekt verwendet.
quelle
Auf SQLite getestet:
Die
max()
Aggregatfunktion stellt sicher, dass der letzte Kauf aus jeder Gruppe ausgewählt wird (setzt jedoch voraus, dass die Datumsspalte in einem Format vorliegt, in dem max () den neuesten angibt - was normalerweise der Fall ist). Wenn Sie Einkäufe mit demselben Datum abwickeln möchten, können Sie verwendenmax(p.date, p.id)
.In Bezug auf Indizes würde ich beim Kauf einen Index verwenden (customer_id, date, [alle anderen Kaufspalten, die Sie in Ihrer Auswahl zurückgeben möchten]).
Das
LEFT OUTER JOIN
(im Gegensatz zuINNER JOIN
) stellt sicher, dass Kunden, die noch nie einen Kauf getätigt haben, ebenfalls einbezogen werden.quelle
Bitte versuchen Sie dies,
quelle