Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL Giant Tables JOIN lässt die Datenbank zusammenbrechen

300.000 Zeilen sind keine riesige Tabelle. Wir sehen häufig 300 Millionen Zeilentabellen.

Das größte Problem bei Ihrer Abfrage besteht darin, dass Sie eine korrelierte Unterabfrage verwenden, die die Unterabfrage für jede Zeile erneut ausführen muss in der äußeren Abfrage.

Oft müssen Sie nicht alles erledigen Ihre Arbeit in einer SQL-Anweisung. Es hat Vorteile, es in mehrere einfachere SQL-Anweisungen aufzuteilen:

  • Einfacher zu codieren.
  • Einfacher zu optimieren.
  • Einfacher zu debuggen.
  • Einfacher zu lesen.
  • Leichter zu warten, falls/wenn Sie neue Anforderungen implementieren müssen.

Anzahl der Käufe

SELECT customer, COUNT(sale) AS number_of_purchases
FROM sales 
GROUP BY customer;

Ein Index für Verkäufe (Kunde, Verkauf) wäre für diese Abfrage am besten geeignet.

Letzter Kaufwert

Dies ist die größte-n-pro-Gruppe Problem, das häufig auftritt.

SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND a.dates < b.dates
WHERE b.customer IS NULL;

Versuchen Sie mit anderen Worten, die Zeile a abzugleichen zu einer hypothetischen Zeile b die denselben Kunden und ein größeres Datum hat. Wenn keine solche Zeile gefunden wird, dann a muss das beste Datum für diesen Kunden haben.

Ein Index für Verkäufe (Kunde, Daten, Verkauf) wäre für diese Abfrage am besten geeignet.

Wenn Sie an diesem größten Datum möglicherweise mehr als einen Verkauf für einen Kunden haben, gibt diese Abfrage mehr als eine Zeile pro Kunde zurück. Sie müssten eine andere Spalte finden, um das Unentschieden zu brechen. Wenn Sie einen Primärschlüssel mit automatischer Erhöhung verwenden, eignet er sich als Tie-Breaker, da er garantiert eindeutig ist und dazu neigt, chronologisch zuzunehmen.

SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL;

Gesamtbetrag der Käufe, wenn er einen positiven Wert hat

SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE sale > 0
GROUP BY customer;

Ein Index für Verkäufe (Kunde, Verkauf) wäre für diese Abfrage am besten geeignet.

Sie sollten erwägen, NULL anstelle von -1 zu verwenden, um einen fehlenden Verkaufswert anzugeben. Aggregatfunktionen wie SUM() und COUNT() ignorieren NULLen, sodass Sie keine WHERE-Klausel verwenden müssen, um Zeilen mit Verkauf <0 auszuschließen.

Re:Ihr Kommentar

Fünf Top-Kunden für Q4 2012

SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE (year, quarter) = (2012, 4) AND sale > 0
GROUP BY customer
ORDER BY total_purchases DESC
LIMIT 5;

Ich würde es gerne mit realen Daten testen, aber ich glaube, dass ein Index für Verkäufe (Jahr, Quartal, Kunde, Verkauf) für diese Abfrage am besten wäre.

Letzter Einkauf für Kunden mit Gesamteinkäufen> 5

SELECT a.customer, a.sale as max_sale
FROM sales a
INNER JOIN sales c ON a.customer=c.customer
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL
GROUP BY a.id
HAVING COUNT(*) > 5;

Wie bei der anderen Abfrage mit den größten n pro Gruppe oben wäre ein Index für Verkäufe (Kunde, Daten, Verkauf) für diese Abfrage am besten geeignet. Es kann wahrscheinlich nicht sowohl den Join als auch die Gruppierung optimieren, daher wird dies zu einer temporären Tabelle führen. Aber zumindest wird es nur eine temporäre Tabelle statt vieler machen.

Diese Abfragen sind komplex genug. Sie sollten nicht versuchen, eine einzelne SQL-Abfrage zu schreiben, die alles liefern kann dieser Ergebnisse. Denken Sie an das klassische Zitat von Brian Kernighan: