PERF: topic_view participant post count: don't send back ID list (#10210)

On large topics, the cost of sending the entire post ID list back over to the database is signficant. Just have the DB recalculate the list of visible posts instead.
This commit is contained in:
Kane York 2020-07-13 18:42:09 -07:00 committed by GitHub
parent ab77707c1e
commit 8ddd45d524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 6 deletions

View File

@ -31,6 +31,10 @@ module TopicGuardian
is_staff? && SiteSetting.enable_whispers? is_staff? && SiteSetting.enable_whispers?
end end
def can_see_whispers?(_topic)
is_staff?
end
def can_publish_topic?(topic, category) def can_publish_topic?(topic, category)
is_staff? && can_see?(topic) && can_create_topic?(category) is_staff? && can_see?(topic) && can_create_topic?(category)
end end

View File

@ -366,21 +366,24 @@ class TopicView
if is_mega_topic? if is_mega_topic?
{} {}
else else
post_ids = unfiltered_post_ids post_types = [Post.types[:regular], Post.types[:moderator_action]]
if @guardian.can_see_whispers?(@topic)
return {} if post_ids.blank? post_types << Post.types[:whisper]
end
sql = <<~SQL sql = <<~SQL
SELECT user_id, count(*) AS count_all SELECT user_id, count(*) AS count_all
FROM posts FROM posts
WHERE id in (:post_ids) WHERE topic_id = :topic_id
AND post_type IN (:post_types)
AND user_id IS NOT NULL AND user_id IS NOT NULL
AND posts.deleted_at IS NULL
GROUP BY user_id GROUP BY user_id
ORDER BY count_all DESC ORDER BY count_all DESC
LIMIT #{MAX_PARTICIPANTS} LIMIT #{MAX_PARTICIPANTS}
SQL SQL
Hash[*DB.query_single(sql, post_ids: post_ids)] Hash[*DB.query_single(sql, topic_id: @topic.id, post_types: post_types)]
end end
end end
end end

View File

@ -287,7 +287,7 @@ describe TopicView do
it 'returns the two posters with their appropriate counts' do it 'returns the two posters with their appropriate counts' do
Fabricate(:post, topic: topic, user: evil_trout, post_type: Post.types[:whisper]) Fabricate(:post, topic: topic, user: evil_trout, post_type: Post.types[:whisper])
expect(topic_view.post_counts_by_user.to_a).to match_array([[first_poster.id, 2], [evil_trout.id, 2]]) expect(TopicView.new(topic.id, admin).post_counts_by_user.to_a).to match_array([[first_poster.id, 2], [evil_trout.id, 2]])
expect(TopicView.new(topic.id, first_poster).post_counts_by_user.to_a).to match_array([[first_poster.id, 2], [evil_trout.id, 1]]) expect(TopicView.new(topic.id, first_poster).post_counts_by_user.to_a).to match_array([[first_poster.id, 2], [evil_trout.id, 1]])
end end