En termes de performances, ces sous-requêtes corrélées peuvent manger votre déjeuner. Et dévorez également votre boîte à lunch, pour les grands ensembles, à cause de la façon dont MySQL les traite. Chacune de ces sous-requêtes est exécutée pour chaque ligne renvoyée dans la requête externe. Et cela peut devenir très coûteux pour les grands ensembles.
Une autre approche consiste à utiliser une vue en ligne pour matérialiser les goûts et les aversions pour tout le contenu, puis à effectuer une opération de jointure.
Mais cette approche peut également être coûteuse, en particulier lorsque vous n'avez besoin que du "compte" des votes pour seulement quelques lignes de contenu, sur un milliard de lignes. Souvent, il existe un prédicat de la requête externe qui peut également être incorporé dans la vue en ligne, pour limiter le nombre de lignes qui doivent être examinées et renvoyées.
Nous souhaitons utiliser une jointure OUTER pour cette vue en ligne, afin qu'elle renvoie un résultat équivalent à votre requête ; renvoyer une ligne de content
lorsqu'il n'y a pas de lignes correspondantes dans le vote
tableau.
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 ... ]
Notez que la requête de vue intégrée (alias v
) va examiner CHAQUE ligne des votes
table. Si vous n'avez besoin que d'un sous-ensemble, envisagez d'ajouter un prédicat approprié (soit dans une clause WHERE, soit en tant que JOIN vers une autre table). Il n'y a aucune indication du [... OTHER STUFF ...]
dans votre requête si elle ne renvoie que quelques lignes de content
ou si vous avez besoin de toutes les lignes parce que vous commandez par likes
, etc.
Pour un petit nombre de lignes sélectionnées dans le content
table, l'utilisation des sous-requêtes corrélées (comme dans votre requête) peut en fait être plus rapide que de matérialiser une énorme vue en ligne et d'effectuer une opération de jointure sur celle-ci.
Oh... et pour les deux requêtes, il va sans dire qu'un index approprié sur les votes
tableau avec une première colonne de cId
profitera aux performances. Pour la vue en ligne, vous ne voulez pas que MySQL ait à effectuer un filesort
opération sur toutes ces lignes pour faire le GROUP BY. Et pour les sous-requêtes corrélées, vous voulez qu'elles utilisent une analyse de plage d'index, pas une analyse complète.