【问题标题】:Nested query performance嵌套查询性能
【发布时间】:2015-07-07 14:41:18
【问题描述】:

我在下面有两个问题。第一个有一个嵌套选择。第二个使用 group by 子句。

select
  posts.*,
  (select count(*) from comments where comments.post_id = posts.id and comments.is_approved = 1) as comments_count
from
  posts 

select
  posts.*,
  count(comments.id) comments_count
from
  posts

  left join comments on
     comments.post_id = posts.id 
group by
  posts.*

据我了解,第一个查询更糟糕,因为它必须对帖子中的每条记录进行选择,而第二个查询则没有。

这是真的还是假的?

【问题讨论】:

  • 第二个根本不行,你需要加入commentsposts。此外,我从来没有这样分组,所以我不能确定,但​​即使它是合法的语法,你的GROUP BY 也会同样有效,而且可能更快,如果你只是做了GROUP BY posts.post_id。此外,一旦正确编写,我希望后者更快。
  • 谢谢...对不起,我错过了包括左连接,已编辑以包含它。

标签: mysql


【解决方案1】:

与所有性能问题一样,您应该使用数据测试系统的性能。

但是,我希望第一个性能更好,索引正确。正确的索引:

select p.*,
       (select count(*)
        from comments c
        where c.post_id = p.id and c.is_approved = 1
       ) as comments_count
from posts p

comments(post_id, is_approved)

MySQL 通过文件排序实现group by。此版本保存对所有数据的文件排序。我的猜测是这会比第二种方法更快。

注意:group by posts.* 不是有效的语法。我认为这仅用于说明目的。

【讨论】:

  • 这是推测,但在我看来,OP 想根据帖子 ID 计算 cmets,所以只对帖子 ID 和 COUNT(*) 进行聚合会更有效吗?跨度>
  • 1.在这种情况下,MySQL 不会进行文件排序。 2. 即使是这样,连接也会比依赖子查询快得多。
【解决方案2】:

这是我这样做的标准方式(使用 LEFT JOIN,SUM 还可以让您知道哪些帖子没有 cmets。)

SELECT posts.*
   , SUM(IF(comments.id IS NULL, 0, 1)) AS comments_count
FROM posts
LEFT JOIN comments USING (post_id)
GROUP BY posts.post_id
;

但如果我尝试更快,这可能会更好。

SELECT posts.*, IFNULL(subQ.comments_count, 0) AS comments_count
FROM posts
LEFT JOIN (
   SELECT post_id, COUNT(1) AS comments_count 
   FROM comments 
   GROUP BY post_id
) As subQ
USING (post_id)
;

【讨论】:

    【解决方案3】:

    经过一番研究,我发现这两个查询之间没有时间差异

    Benchmark.bm do |b|
     b.report('joined') do
       1000.times do
         ActiveRecord::Base.connection.execute('
           select
              p.id,
              (select count(c.id) from comments c where c.post_id = p.id) comment_count
           from
              posts l;')
       end
     end
    
     b.report('nested') do
       1000.times do
         ActiveRecord::Base.connection.execute('
           select
              p.id,
              count(c.id) comment_count
           from
              posts File.join(File.dirname(__FILE__), *%w[rel path here])
    
              left join comments c on
                c.post_id = p.id
           group by
              p.id;')
       end
     end
    end
    
           user     system      total        real
    nested  2.120000   0.900000   3.020000 (  3.349015)
    joined  2.110000   0.990000   3.100000 (  3.402986)
    

    但是我确实注意到,在对两个查询运行解释时,第一个查询中可能会出现更多索引。这让我认为,如果选择中所需的属性发生变化,这是一个更好的选择。

    【讨论】:

      猜你喜欢
      • 2016-01-31
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 2016-12-25
      • 2021-05-06
      • 2018-04-12
      • 2019-10-13
      • 1970-01-01
      相关资源
      最近更新 更多