sql >> Databáze >  >> RDS >> Mysql

MySQL obrovské tabulky JOIN způsobí kolaps databáze

300 000 řádků není velká tabulka. Často vidíme 300 milionů řádkových tabulek.

Největší problém s vaším dotazem je, že používáte korelovaný poddotaz, takže musí znovu spustit poddotaz pro každý řádek ve vnějším dotazu.

Často se stává, že nemusíte dělat vše svou práci v jednom SQL příkazu. Rozdělení na několik jednodušších příkazů SQL má své výhody:

  • Snazší kódování.
  • Snazší optimalizace.
  • Snazší ladění.
  • Snazší čtení.
  • Snazší údržba, pokud/když musíte implementovat nové požadavky.

Počet nákupů

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

Pro tento dotaz by byl nejlepší index prodeje (zákazník, prodej).

Hodnota posledního nákupu

Toto je největší-n-na-skupinu problém, který se často objevuje.

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;

Jinými slovy, zkuste najít shodu na řádku a na hypotetický řádek b který má stejného zákazníka a větší datum. Pokud takový řádek není nalezen, pak a musí mít pro daného zákazníka největší datum.

Pro tento dotaz by byl nejlepší index prodeje (zákazník, data, prodej).

Pokud můžete mít více než jeden prodej pro zákazníka k tomuto největšímu datu, tento dotaz vrátí více než jeden řádek na zákazníka. Budete muset najít jiný sloupec, abyste zlomili remízu. Pokud používáte primární klíč s automatickým přírůstkem, je vhodný jako remíza, protože je zaručeno, že je jedinečný a má tendenci chronologicky narůstat.

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;

Celkový objem nákupů, když má kladnou hodnotu

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

Pro tento dotaz by byl nejlepší index prodeje (zákazník, prodej).

Měli byste zvážit použití NULL k označení chybějící hodnoty prodeje namísto -1. Agregační funkce jako SUM() a COUNT() ignorují hodnoty NULL, takže k vyloučení řádků s prodejem <0 nemusíte používat klauzuli WHERE.

Re:váš komentář

Pět nejlepších zákazníků za 4. čtvrtletí 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;

Chtěl bych to otestovat na skutečných datech, ale věřím, že pro tento dotaz by byl nejlepší index prodeje (rok, čtvrtletí, zákazník, prodej).

Poslední nákup pro zákazníky s celkovým počtem nákupů> 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;

Stejně jako ve výše uvedeném jiném dotazu s největším počtem n na skupinu by pro tento dotaz byl nejlepší index prodeje (zákazník, data, prodej). Pravděpodobně nemůže optimalizovat spojení i skupinu pomocí, takže to způsobí dočasnou tabulku. Ale alespoň to udělá pouze jednu dočasnou tabulku místo mnoha.

Tyto dotazy jsou dostatečně složité. Neměli byste se pokoušet napsat jediný SQL dotaz, který může poskytnout vše těchto výsledků. Vzpomeňte si na klasický citát od Briana Kernighana:



  1. C# Oracle Stored Procedure Parameter Order

  2. Jak nastavit automatické převzetí služeb při selhání pro databázi Moodle MySQL

  3. Který jar na webovém serveru/jiných zdrojích by mohl mít třídu:oracle.security.jps.ee.http.JpsFilter?

  4. Jak změnit výchozí formát nls_date_format pro klienta Oracle jdbc