sql >> Database >  >> RDS >> Mysql

Grote MySQL-tabellen JOIN zorgt ervoor dat de database instort

300k rijen is geen enorme tafel. We zien vaak 300 miljoen rijtabellen.

Het grootste probleem met uw zoekopdracht is dat u een gecorreleerde subquery gebruikt, dus het moet de subquery voor elke rij opnieuw uitvoeren in de buitenste vraag.

Het is vaak zo dat u niet alles hoeft te doen uw werk in één SQL-statement. Het opsplitsen in verschillende eenvoudigere SQL-instructies heeft voordelen:

  • Makkelijker te coderen.
  • Makkelijker te optimaliseren.
  • Makkelijker te debuggen.
  • Makkelijker te lezen.
  • Makkelijker te onderhouden als/wanneer u nieuwe vereisten moet implementeren.

Aantal aankopen

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

Een index op verkoop (klant, verkoop) zou het beste zijn voor deze zoekopdracht.

Laatste aankoopwaarde

Dit is de greatest-n-per-group probleem dat vaak voorkomt.

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;

Met andere woorden, probeer rij a . te matchen naar een hypothetische rij b die dezelfde klant en een grotere datum heeft. Als zo'n rij niet wordt gevonden, dan a moet de beste datum voor die klant hebben.

Een index op verkopen (klant, datums, verkoop) zou het beste zijn voor deze zoekopdracht.

Als u op die beste datum mogelijk meer dan één verkoop voor een klant heeft, levert deze zoekopdracht meer dan één rij per klant op. Je zou een andere kolom moeten vinden om de band te verbreken. Als u een primaire sleutel voor automatisch verhogen gebruikt, is deze geschikt als gelijkspel omdat deze gegarandeerd uniek is en de neiging heeft om chronologisch toe te nemen.

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;

Totaal aantal aankopen, wanneer het een positieve waarde heeft

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

Een index op verkoop (klant, verkoop) zou het beste zijn voor deze zoekopdracht.

Overweeg om NULL te gebruiken om een ​​ontbrekende verkoopwaarde aan te duiden in plaats van -1. Geaggregeerde functies zoals SUM() en COUNT() negeren NULL's, dus u hoeft geen WHERE-clausule te gebruiken om rijen met sale <0 uit te sluiten.

Re:jouw reactie

Top vijf klanten voor het vierde kwartaal van 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;

Ik zou het willen testen met echte gegevens, maar ik denk dat een index op verkoop (jaar, kwartaal, klant, verkoop) het beste zou zijn voor deze zoekopdracht.

Laatste aankoop voor klanten met een totaal aantal aankopen> 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;

Net als in de andere grootste-n-per-groep-query hierboven, zou een index op verkopen (klant, datums, verkoop) het beste zijn voor deze zoekopdracht. Het kan waarschijnlijk niet zowel de join als de groep optimaliseren door, dus dit zal een tijdelijke tabel opleveren. Maar het zal in ieder geval maar één tijdelijke tafel doen in plaats van veel.

Deze vragen zijn al complex genoeg. Je moet niet proberen een enkele SQL-query te schrijven die alles . kan geven van deze resultaten. Denk aan het klassieke citaat van Brian Kernighan:



  1. Zijn tabelnamen in MySQL hoofdlettergevoelig?

  2. SQL-query om geregistreerde gebruikers per dag te tellen

  3. Hoe de Haversine-formule in mysql te versnellen?

  4. hoe een door tabs gescheiden bestand in mysql in te voegen met relation