Em termos de desempenho, essas subconsultas correlacionadas podem comer seu almoço. E devore sua lancheira também, para grandes conjuntos, por causa da maneira como o MySQL os processa. Cada uma dessas subconsultas é executada para cada linha retornada na consulta externa. E isso pode ficar muito caro para grandes conjuntos.
Uma abordagem alternativa é usar uma visualização em linha para materializar os gostos e desgostos de todo o conteúdo e, em seguida, fazer uma operação de junção para isso.
Mas essa abordagem também pode ser cara, principalmente quando você só precisa da "contagem" de votos para apenas algumas linhas de conteúdo, de um zilhão de linhas. Muitas vezes, há um predicado da consulta externa que também pode ser incorporado à exibição em linha, para limitar o número de linhas que precisam ser examinadas e retornadas.
Queremos usar uma junção OUTER para essa visualização em linha, para que ela retorne um resultado equivalente à sua consulta; retornando uma linha de
content
quando não há linhas correspondentes no vote
tabela. 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 ... ]
Observe que a consulta de visualização embutida (alias como
v
) examinará TODAS as linhas dos votes
tabela. Se você precisar apenas de um subconjunto, considere adicionar um predicado apropriado (em uma cláusula WHERE ou como um JOIN em outra tabela). Não há indicação do [... OTHER STUFF ...]
em sua consulta se está retornando apenas algumas linhas de content
ou se você estiver precisando de todas as linhas porque está ordenando por likes
, etc Para um pequeno número de linhas selecionadas do
content
table, usar as subconsultas correlacionadas (como em sua consulta) pode ser realmente mais rápido do que materializar uma enorme exibição em linha e executar uma operação de junção nela. Ah... e para ambas as consultas, nem é preciso dizer que um índice apropriado no
votes
tabela com uma coluna inicial de cId
beneficiará o desempenho. Para a visualização inline, você não quer a sobrecarga do MySQL ter que executar um filesort
operação em todas essas linhas para fazer o GROUP BY. E para as subconsultas correlacionadas, você deseja que elas usem uma varredura de intervalo de índice, não uma varredura completa.