PERF: Reduce records queried in `UserStat.update_first_unread_pm`.

The inefficiency here is that we were previously fetching all the
records from `TopicAllowedUser` before filtering against a limited subset of
users based on `User#last_seen_at`.
This commit is contained in:
Alan Guo Xiang Tan 2021-11-19 10:50:01 +08:00
parent 20f5474be9
commit b8c8909a9d
No known key found for this signature in database
GPG Key ID: 3F656E28E3AADEF1
1 changed files with 28 additions and 33 deletions

View File

@ -24,40 +24,35 @@ class UserStat < ActiveRecord::Base
SET first_unread_pm_at = COALESCE(Z.min_date, :now) SET first_unread_pm_at = COALESCE(Z.min_date, :now)
FROM ( FROM (
SELECT SELECT
Y.user_id, u1.id user_id,
Y.min_date X.min_date
FROM ( FROM users u1
LEFT JOIN (
SELECT SELECT
u1.id user_id, tau.user_id,
X.min_date MIN(t.updated_at) min_date
FROM users u1 FROM topic_allowed_users tau
LEFT JOIN ( INNER JOIN topics t ON t.id = tau.topic_id
SELECT INNER JOIN users u ON u.id = tau.user_id
tau.user_id, LEFT JOIN topic_users tu ON t.id = tu.topic_id AND tu.user_id = tau.user_id
MIN(t.updated_at) min_date WHERE t.deleted_at IS NULL
FROM topic_allowed_users tau AND t.archetype = :archetype
INNER JOIN topics t ON t.id = tau.topic_id AND tu.last_read_post_number < CASE
INNER JOIN users u ON u.id = tau.user_id WHEN u.admin OR u.moderator
LEFT JOIN topic_users tu ON t.id = tu.topic_id AND tu.user_id = tau.user_id THEN t.highest_staff_post_number
WHERE t.deleted_at IS NULL ELSE t.highest_post_number
AND t.archetype = :archetype END
AND tu.last_read_post_number < CASE AND (COALESCE(tu.notification_level, 1) >= 2)
WHEN u.admin OR u.moderator AND tau.user_id IN (
THEN t.highest_staff_post_number SELECT id
ELSE t.highest_post_number FROM users
END WHERE last_seen_at IS NOT NULL
AND (COALESCE(tu.notification_level, 1) >= 2) AND last_seen_at > :last_seen
GROUP BY tau.user_id ORDER BY last_seen_at DESC
) AS X ON X.user_id = u1.id LIMIT :limit
) AS Y )
WHERE Y.user_id IN ( GROUP BY tau.user_id
SELECT id ) AS X ON X.user_id = u1.id
FROM users
WHERE last_seen_at IS NOT NULL
AND last_seen_at > :last_seen
ORDER BY last_seen_at DESC
LIMIT :limit
)
) AS Z ) AS Z
WHERE us.user_id = Z.user_id WHERE us.user_id = Z.user_id
SQL SQL