discourse/app
Isaac Janzen db10dd5319
PERF: Improve performance of most_replied_to_users (#26373)
This PR improves the performance of the `most_replied_to_users` method on the `UserSummary` model.

### Old Query
```ruby
    post_query
      .joins(
        "JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number",
      )
      # We are removing replies by @user, but we can simplify this by getting the using the user_id on the posts.
      .where("replies.user_id <> ?", @user.id)
      .group("replies.user_id")
      .order("COUNT(*) DESC")
      .limit(MAX_SUMMARY_RESULTS)
      .pluck("replies.user_id, COUNT(*)")
      .each { |r| replied_users[r[0]] = r[1] }
```
 
### Old Query with corrections

```ruby
post_query
  .joins(
    "JOIN posts replies ON posts.topic_id = replies.topic_id AND replies.reply_to_post_number = posts.post_number",
  )
  # Remove replies by @user but instead look on loaded posts (we do this so we don't count self replies)
  .where("replies.user_id <> posts.user_id")
  .group("replies.user_id")
  .order("COUNT(*) DESC")
  .limit(MAX_SUMMARY_RESULTS)
  .pluck("replies.user_id, COUNT(*)")
  .each { |r| replied_users[r[0]] = r[1] }
```

### New Query
```ruby
    post_query
      .joins(
        "JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number",
      )
      # Only include regular posts in our joins, this makes sure we don't have the bloat of loading private messages
      .joins(
        "JOIN topics ON replies.topic_id = topics.id AND topics.archetype <> 'private_message'",
      )
      # Only include visible post types, so exclude posts like whispers, etc
      .joins(
        "AND replies.post_type IN (#{Topic.visible_post_types(@user, include_moderator_actions: false).join(",")})",
      )
      .where("replies.user_id <> posts.user_id")
      .group("replies.user_id")
      .order("COUNT(*) DESC")
      .limit(MAX_SUMMARY_RESULTS)
      .pluck("replies.user_id, COUNT(*)")
      .each { |r| replied_users[r[0]] = r[1] }
```

# Conclusion

`most_replied_to_users` was untested, so I introduced a test for the logic, and have confirmed that it passes on both the new query **AND** the old query. 

Thank you @danielwaterworth for the debugging assistance.
2024-04-03 14:20:54 -06:00
..
assets FIX: add home-logo outlet args to non glimmer version (#26495) 2024-04-03 21:44:32 +05:30
controllers DEV: add logo URL and locale details to the Discover stats. (#26320) 2024-04-04 00:22:28 +05:30
helpers DEV: allow themes to render their own custom homepage (#26291) 2024-04-02 11:05:08 -04:00
jobs DEV: Add skip_email_bulk_invites hidden site setting (#26430) 2024-03-29 13:22:00 -04:00
mailers FIX: Add higher read & open timeouts for group SMTP emails (#24593) 2023-11-28 15:32:59 +10:00
models PERF: Improve performance of most_replied_to_users (#26373) 2024-04-03 14:20:54 -06:00
serializers DEV: add logo URL and locale details to the Discover stats. (#26320) 2024-04-04 00:22:28 +05:30
services UX: Improvements to user tips (#26480) 2024-04-03 11:43:56 -04:00
views DEV: allow themes to render their own custom homepage (#26291) 2024-04-02 11:05:08 -04:00