sql >> Database >  >> RDS >> Mysql

Optimaliseren van mysql-query (leuk/niet leuk)

Wat de prestaties betreft, kunnen die gecorreleerde subquery's uw lunch opeten. En verslind ook je lunchbox, voor grote sets, vanwege de manier waarop MySQL ze verwerkt. Elk van die subquery's wordt uitgevoerd voor elke rij die wordt geretourneerd in de buitenste query. En dat kan erg duur worden voor grote sets.

Een alternatieve benadering is om een ​​inline-weergave te gebruiken om de sympathieën en antipathieën voor alle inhoud te concretiseren, en daar vervolgens een samenvoegbewerking op uit te voeren.

Maar deze aanpak kan ook duur zijn, vooral als je de stemmen maar nodig hebt voor slechts een paar inhoudsrijen, uit een biljoen rijen. Vaak is er een predikaat uit de buitenste query dat ook kan worden opgenomen in de inline-weergave, om het aantal rijen te beperken dat moet worden onderzocht en geretourneerd.

We willen een OUTER-join gebruiken voor die inline-weergave, dus het retourneert een resultaat dat gelijk is aan uw zoekopdracht; een rij retourneren uit content wanneer er geen overeenkomende rijen zijn in de vote tafel.

SELECT [... BUNCH OF FIELDS ...]
     , COALESCE(v.likes,0) AS likes
     , COALESCE(v.dislikes,0) AS dislikes
     , COALESCE(v.myvote,'.Constants::NO_VOTE.') AS myvote
  FROM content c
  LEFT
  JOIN ( SELECT vt.cId
              , SUM(vt.vote = '.Constants::LIKE.') AS likes
              , SUM(vt.vote = '.Constants::DISLIKE.') AS dislikes
              , MAX(IF(vt.userId = '.USER_ID.',vt.vote,NULL)) AS myvote
           FROM votes vt
          GROUP
             BY vt.cId
       ) v
    ON v.cId = c.contentId

       [... OTHER STUFF ... ]

Merk op dat de inline view-query (alias v ) gaat ELKE rij bekijken van de votes tafel. Als je alleen een subset nodig hebt, overweeg dan om een ​​geschikt predikaat toe te voegen (in een WHERE-clausule of als JOIN aan een andere tabel). Er is geen indicatie van de [... OTHER STUFF ...] in uw vraag of het slechts een paar rijen retourneert van content of als je alle rijen nodig hebt omdat je bestelt op likes , enz.

Voor een klein aantal rijen geselecteerd uit de content tabel, kan het gebruik van de gecorreleerde subquery's (zoals in uw query) zelfs sneller zijn dan het realiseren van een enorme inline-weergave en het uitvoeren van een join-bewerking ertegen.

Oh... en voor beide zoekopdrachten is het vanzelfsprekend dat een geschikte index op de votes tabel met een leidende kolom van cId zal de prestaties ten goede komen. Voor de inline-weergave wilt u niet dat de overhead van MySQL een filesort moet uitvoeren bewerking op al die rijen om de GROUP BY. En voor de gecorreleerde subquery's wilt u dat ze een indexbereikscan gebruiken, geen volledige scan.



  1. Hoe MapReduce werkt in Hadoop

  2. Hoe selecteer ik slechts 1 rij van Oracle SQL?

  3. ScrollableResults van Hibernate gebruiken om langzaam 90 miljoen records te lezen

  4. Is er een manier om een ​​filesort te vermijden wanneer de volgorde van verschilt van de waar-clausule?