Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Otimizando a consulta mysql (gostos/desgostos)


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.