Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Ogromne tabele MySQL JOIN powoduje upadek bazy danych

300 tys. wierszy to nie ogromny stół. Często widzimy 300 milionów tabel wierszy.

Największym problemem z zapytaniem jest to, że używasz skorelowanego podzapytania, więc musi ono ponownie wykonać podzapytanie dla każdego wiersza w zewnętrznym zapytaniu.

Często zdarza się, że nie musisz robić wszystkich swoją pracę w jednej instrukcji SQL. Rozbicie go na kilka prostszych instrukcji SQL ma zalety:

  • Łatwiejsze kodowanie.
  • Łatwiejsza optymalizacja.
  • Łatwiejsze debugowanie.
  • Łatwiejszy do czytania.
  • Łatwiejsze w utrzymaniu, jeśli/kiedy musisz wdrożyć nowe wymagania.

Liczba zakupów

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

Dla tego zapytania najlepszy byłby indeks sprzedaży (klient, sprzedaż).

Wartość ostatniego zakupu

To jest największe-n-per-group problem, który często się pojawia.

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;

Innymi słowy, spróbuj dopasować wiersz a do hipotetycznego wiersza b który ma tego samego klienta i większą datę. Jeśli nie znaleziono takiego wiersza, to a musi mieć najdłuższą datę dla tego klienta.

Indeks sprzedaży (klient, terminy, sprzedaż) byłby najlepszy dla tego zapytania.

Jeśli w tym największym dniu możesz mieć więcej niż jedną sprzedaż dla klienta, to zapytanie zwróci więcej niż jeden wiersz na klienta. Musiałbyś znaleźć inną kolumnę, aby zerwać remis. Jeśli używasz klucza podstawowego z automatycznym przyrostem, jest on odpowiedni jako łamiący remis, ponieważ gwarantuje, że jest unikalny i ma tendencję do zwiększania się chronologicznie.

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;

Łączna liczba zakupów, gdy ma wartość dodatnią

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

Dla tego zapytania najlepszy byłby indeks sprzedaży (klient, sprzedaż).

Należy rozważyć użycie NULL do oznaczenia brakującej wartości sprzedaży zamiast -1. Funkcje agregujące, takie jak SUM() i COUNT(), ignorują wartości NULL, więc nie musisz używać klauzuli WHERE, aby wykluczyć wiersze ze sprzedażą <0.

Odp.:Twój komentarz

Pięciu największych klientów w czwartym kwartale 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;

Chciałbym przetestować to z rzeczywistymi danymi, ale uważam, że indeks sprzedaży (rok, kwartał, klient, sprzedaż) byłby najlepszy dla tego zapytania.

Ostatni zakup dla klientów, których łączna liczba zakupów> 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;

Podobnie jak w przypadku innego zapytania o największej liczbie na grupę powyżej, dla tego zapytania najlepszy byłby indeks sprzedaży (klient, daty, sprzedaż). Prawdopodobnie nie może zoptymalizować zarówno łączenia, jak i grupowania, więc spowoduje to powstanie tabeli tymczasowej. Ale przynajmniej zrobi tylko jedną tabelę tymczasową zamiast wielu.

Te zapytania są wystarczająco złożone. Nie powinieneś próbować napisać pojedynczego zapytania SQL, które może dać wszystko tych wyników. Zapamiętaj klasyczny cytat Briana Kernighana:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Uzyskaj SUM w GROUP BY z JOIN przy użyciu MySQL

  2. Połącz pola wierszy o tym samym identyfikatorze w MySQL

  3. Jak wstawiać obrazy w blob w tabeli mysql, używając tylko składni sql (bez PHP)?

  4. Google Cloud SQL SSL nie przechodzi weryfikacji certyfikatu równorzędnego

  5. Kiedy używać mysql_real_escape_string()