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?
end
def can_see_whispers?(_topic)
is_staff?
end
def can_publish_topic?(topic, category)
is_staff? && can_see?(topic) && can_create_topic?(category)
end

View File

@ -366,21 +366,24 @@ class TopicView
if is_mega_topic?
{}
else
post_ids = unfiltered_post_ids
return {} if post_ids.blank?
post_types = [Post.types[:regular], Post.types[:moderator_action]]
if @guardian.can_see_whispers?(@topic)
post_types << Post.types[:whisper]
end
sql = <<~SQL
SELECT user_id, count(*) AS count_all
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 posts.deleted_at IS NULL
GROUP BY user_id
ORDER BY count_all DESC
LIMIT #{MAX_PARTICIPANTS}
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

View File

@ -287,7 +287,7 @@ describe TopicView do
it 'returns the two posters with their appropriate counts' do
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]])
end