我需要重写为连接优化的Mysql查询

时间:2011-02-28 00:07:21

标签: mysql sql join subquery

我真的需要一些关于此查询的帮助。我有5个选择子查询。

-

select s.id,
       s.user_id,
       m.photo                         as profile_photo,
       CONCAT(m.name, ' ', m.lastname) as fullname,
       s.title,
       s.date,
       s.photo,
       s.city,
       (select count(c.id)
        from   s_comments as c
        where  c.story_id = s.id)      as comments_sum,
       (select SUM(important)
        from   s_user_votes as v1
        where  v1.story_id = s.id)     as v_important,
       (select SUM(fun)
        from   s_user_votes as v2
        where  v2.story_id = s.id)     as v_fun,
       (select SUM(interesting)
        from   s_user_votes as v3
        where  v3.story_id = s.id)     as v_interesting,
       (select SUM(boring)
        from   s_user_votes as v4
        where  v4.story_id = s.id)     as v_boring
from   stories as s,
       members as m
where  s.user_id = m.id
order  by v_interesting desc,
          v_boring asc,
          s.date desc
limit  50;

-

1 个答案:

答案 0 :(得分:0)

4个子查询只是检索同一个表(s_user_votes)中不同列的聚合,因此很容易合并到单个join中。

我使用了left [outer] join,因此保留了原始语义(如果一个故事没有用户投票,它仍应出现在结果中)。

另一个子查询位于不同的表(s_comments)上。我已将其放入派生表中,而不是直接连接到它,以确保每个故事最多只返回1行。

这可以防止多个评论或多个用户投票的故事会导致返回的行数相乘而导致SUM计算混乱的问题。

我还在故事GROUP BY上添加了id(在MySQL中,这足以让其他RDBMS需要您列出所有非聚合列)

select s.id,
       s.user_id,
       m.photo                         as profile_photo,
       CONCAT(m.name, ' ', m.lastname) as fullname,
       s.title,
       s.date,
       s.photo,
       s.city,
       c.comments_sum,
       SUM(v.important)                as v_important,
       SUM(v.fun)                      as v_fun,
       SUM(v.interesting)              as v_interesting,
       SUM(v.boring)                   as v_boring
from   stories as s
       join members as m
         on s.user_id = m.id
       left join (select story_id,
                         count(story_id) as comments_sum
                  from   s_comments
                  group  by story_id) as c /*<-- Can't remember if "as" needed here in MySQL*/
         on c.story_id = s.id
       left join s_user_votes as v
         on v.story_id = s.id
group  by s.id
order  by v_interesting desc,
          v_boring asc,
          s.date desc
limit  50;