Mysql
 sql >> Database >  >> RDS >> Mysql

Ottimizzazione della query MySQL (mi piace/non mi piace)

In termini di prestazioni, quelle sottoquery correlate possono consumare il tuo pranzo. E divora anche il tuo pranzo al sacco, per i set di grandi dimensioni, a causa del modo in cui MySQL li elabora. Ognuna di queste sottoquery viene eseguita per ogni riga restituita nella query esterna. E questo può diventare molto costoso per i set di grandi dimensioni.

Un approccio alternativo consiste nell'utilizzare una visualizzazione in linea per materializzare i Mi piace e i Non mi piace per tutti i contenuti, quindi eseguire un'operazione di unione a quello.

Ma anche questo approccio può essere costoso, in particolare quando hai bisogno che il voto "conta" solo per poche righe di contenuto, su un miliardo di righe. Spesso esiste un predicato della query esterna che può essere incorporato anche nella vista inline, per limitare il numero di righe che devono essere esaminate e restituite.

Vogliamo utilizzare un join OUTER a quella vista inline, quindi restituisce un risultato equivalente alla tua query; restituendo una riga da content quando non ci sono righe corrispondenti nel vote tabella.

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 ... ]

Nota che la query della vista in linea (alias v ) esaminerà OGNI singola riga dei votes tavolo. Se hai solo bisogno di un sottoinsieme, considera l'aggiunta di un predicato appropriato (in una clausola WHERE o come JOIN in un'altra tabella). Non c'è alcuna indicazione da [... OTHER STUFF ...] nella tua query se sta restituendo solo poche righe da content o se hai bisogno di tutte le righe perché stai ordinando per likes , ecc.

Per un numero ridotto di righe selezionate da content tabella, l'utilizzo delle sottoquery correlate (come nella tua query) può essere effettivamente più veloce che materializzare un'enorme vista in linea ed eseguire un'operazione di join su di essa.

Oh... e per entrambe le query, va da sé che un indice appropriato sui votes tabella con una colonna iniziale di cId andrà a beneficio delle prestazioni. Per la vista in linea, non vuoi che il sovraccarico di MySQL debba eseguire un filesort operazione su tutte quelle righe per eseguire il GROUP BY. E per le sottoquery correlate, vuoi che utilizzino una scansione dell'intervallo di indici, non una scansione completa.