2015-07-07 2 views
0

У меня есть два запроса ниже. Первый имеет вложенный выбор. Во втором используется предложение 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.* 

Из моего понимания первый запрос хуже, потому что он должен сделать выбор для каждой записи в сообщениях, где в качестве второго запроса не делает.

Это правда или ложь?

+1

Второй не работает вообще, вам нужно присоединиться к 'comments' в' posts'. Кроме того, я никогда не группировался таким образом, поэтому я не могу быть уверенным, но даже если это юридический синтаксис, ваш «GROUP BY» будет таким же эффективным и, возможно, быстрее, если вы просто сделали «GROUP BY posts.post_id» '. Кроме того, как только правильно написано, я ожидаю, что последнее будет быстрее. – Uueerdo

+0

спасибо ... жаль, что я пропустил, включая левое соединение, отредактированное, чтобы включить его. –

ответ

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.* недопустим синтаксис. Я предполагаю, что это было предназначено только для иллюстрации.

+0

Это предположение, но мне кажется, что OP хочет подсчитывать комментарии на основе идентификатора сообщения, так что было бы более эффективно просто делать агрегацию для идентификатора сообщения и COUNT (*)? – AdamMc331

+0

1. В этом случае MySQL не будет сортировать файлы. 2. Даже если это соединение будет намного быстрее, чем зависимый подзапрос. – Vatev

0

Это стандартный способ, которым я хотел бы сделать это (использование LEFT JOIN, и SUM позволяет также знать, какие сообщения нет ни одного комментария.)

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 
; 

Но если бы я пытался ускорить и это способ доставки be better.

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) 
; 
0

После немного больше исследований я не нашел никакой разницы во времени между двумя запросами

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) 

Однако я заметил, что при запуске объяснить для обоих запросов, больше индексов возможны в первом запросе. Это заставляет меня думать, что это лучший вариант, если атрибуты, необходимые для выбора, изменились.

Смежные вопросы