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.