优化mysql查询(喜欢/不喜欢)

时间:2014-02-26 22:10:44

标签: mysql sql optimization count subquery

我的网站包含用户可以投票的内容(喜欢/不喜欢类似于reddit upvotes)。在选择单个内容时,我运行以下子查询来获取喜欢的数量,不喜欢的数量以及当前用户的投票。

投票存储在单独的表{contentId,userId,vote}

SELECT

[... BUNCH OF FIELDS ...]

(SELECT COUNT(*) FROM votes vt WHERE vt.cId = c.contentId AND vote = '.Constants::LIKE.') AS likes,
(SELECT COUNT(*) FROM votes vt WHERE vt.cId = c.contentId AND vote = '.Constants::DISLIKE.') AS dislikes,
COALESCE((SELECT vote FROM votes vt WHERE vt.cId = c.contentId AND userId = '.USER_ID.'), '.Constants::NO_VOTE.') AS myVote

FROM content

[... OTHER STUFF ... ]

有没有更好的方法来实现这一点(结合这些子查询或其他方式)?

2 个答案:

答案 0 :(得分:3)

就性能而言,那些相关的子查询可以吃你的午餐。因为MySQL处理它们的方式,所以也可以吞食你的午餐盒。对于外部查询中返回的每一行,都会执行每个子查询。对于大型套装而言,这可能会变得非常昂贵。

另一种方法是使用内联视图来实现所有内容的喜欢和不喜欢,然后对其进行连接操作。

但是,这种方法也可能很昂贵,特别是当您只需要对几行内容中的几个内容行进行“计数”投票时。通常,外部查询中有一个谓词也可以合并到内联视图中,以限制需要检查和返回的行数。

我们希望对该内联视图使用OUTER连接,因此它返回与查询等效的结果;当content表中没有匹配的行时,从vote返回一行。

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

请注意,内联视图查询(别名为v)将查看votes表中的每一行。如果您只需要一个子集,那么考虑添加一个适当的谓词(在WHERE子句中或作为JOIN到另一个表)。查询中的[... OTHER STUFF ...]没有任何迹象表明它是从content返回几行还是因为您按likes等排序而需要所有行。

对于从content表中选择的少量行,使用相关子查询(如查询中)实际上比实现大型内联视图并对其执行连接操作更快。

哦......对于这两个查询,不言而喻,votes表上具有前导列cId的适当索引将有利于提高性能。对于内联视图,您不希望MySQL的开销必须对所有这些行执行filesort操作来执行GROUP BY。对于相关子查询,您希望它们使用索引范围扫描,而不是完整扫描。

答案 1 :(得分:0)

您的问题很简单,您返回的每一行都会运行当前的子查询。

您需要加入该数据。您需要更改我添加的代码,以便为您提供正确的计数,但这应该指向正确的方向。

SELECT
    BLAH
    Likes,
    Dislikes
FROM CONTENT as C
INNER JOIN (
    SELECT 
        cID,
        COUNT(votes) as Likes, --you will need to alter this 
        COUNT(votes) as Dislikes --to count your up and downvotes
    FROM Votes
    GROUP BY cID
    ) AS V
    ON  V.cID = C.ContentID
相关问题