mirror of
				https://github.com/discourse/discourse.git
				synced 2025-02-25 18:55:32 -06:00 
			
		
		
		
	PERF: improve performance of unread queries
Figuring out what unread topics a user has is a very expensive operation over time. Users can easily accumulate 10s of thousands of tracking state rows (1 for every topic they ever visit) When figuring out what a user has that is unread we need to join the tracking state records to the topic table. This can very quickly lead to cases where you need to scan through the entire topic table. This commit optimises it so we always keep track of the "first" date a user has unread topics. Then we can easily filter out all earlier topics from the join. We use pg functions, instead of nested queries here to assist the planner.
This commit is contained in:
		@@ -81,6 +81,30 @@ class UserStat < ActiveRecord::Base
 | 
			
		||||
    update_columns(reset_bounce_score_after: nil, bounce_score: 0)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.update_first_topic_unread_at!
 | 
			
		||||
 | 
			
		||||
    exec_sql <<SQL
 | 
			
		||||
    UPDATE user_stats us
 | 
			
		||||
    SET first_topic_unread_at = COALESCE(X.first_unread_at, 'epoch')
 | 
			
		||||
    FROM
 | 
			
		||||
    (
 | 
			
		||||
      SELECT u.id user_id, MIN(last_unread_at) first_unread_at
 | 
			
		||||
      FROM users u
 | 
			
		||||
      JOIN topic_users tu ON tu.user_id = u.id
 | 
			
		||||
      JOIN topics t ON t.id = tu.topic_id
 | 
			
		||||
      WHERE notification_level > 1 AND last_read_post_number < CASE WHEN moderator OR admin
 | 
			
		||||
                                                                THEN t.highest_staff_post_number
 | 
			
		||||
                                                                ELSE t.highest_post_number
 | 
			
		||||
                                                               END
 | 
			
		||||
        AND t.deleted_at IS NULL AND t.archetype <> 'private_message'
 | 
			
		||||
      GROUP BY u.id
 | 
			
		||||
    ) X
 | 
			
		||||
    WHERE X.user_id = us.user_id AND X.first_unread_at <> first_topic_unread_at
 | 
			
		||||
SQL
 | 
			
		||||
 | 
			
		||||
    nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  protected
 | 
			
		||||
 | 
			
		||||
  def trigger_badges
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user