From bdecd697b9de6e50c003a93a8ca9e602dacbad61 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Thu, 13 Jul 2023 09:02:23 +1000 Subject: [PATCH] FIX: more performance improvement for PostAlert job (#22487) Simplified query based on SiteSettings to join only relevant user_options rows. In addition, index was added to 'watched_precedence_over_muted` column in `user_options` table to speed up query --- app/models/category_user.rb | 7 +++-- app/models/topic_user.rb | 5 +-- app/models/user_option.rb | 5 +-- app/services/post_alerter.rb | 31 ++++++++++++------- ...edence_over_muted_index_to_user_options.rb | 7 +++++ ...notification_level_index_to_topic_users.rb | 7 +++++ ...ification_level_index_to_category_users.rb | 7 +++++ 7 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 db/migrate/20230707031122_add_watched_precedence_over_muted_index_to_user_options.rb create mode 100644 db/migrate/20230712011946_add_topic_id_notification_level_index_to_topic_users.rb create mode 100644 db/migrate/20230712013248_add_category_id_notification_level_index_to_category_users.rb diff --git a/app/models/category_user.rb b/app/models/category_user.rb index 4623567656f..d7cee509c71 100644 --- a/app/models/category_user.rb +++ b/app/models/category_user.rb @@ -289,7 +289,8 @@ end # # Indexes # -# idx_category_users_category_id_user_id (category_id,user_id) UNIQUE -# idx_category_users_user_id_category_id (user_id,category_id) UNIQUE -# index_category_users_on_user_id_and_last_seen_at (user_id,last_seen_at) +# idx_category_users_category_id_user_id (category_id,user_id) UNIQUE +# idx_category_users_user_id_category_id (user_id,category_id) UNIQUE +# index_category_users_on_category_id_and_notification_level (category_id,notification_level) +# index_category_users_on_user_id_and_last_seen_at (user_id,last_seen_at) # diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index 6b58cfbe464..e8c15fd6d51 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -582,6 +582,7 @@ end # # Indexes # -# index_topic_users_on_topic_id_and_user_id (topic_id,user_id) UNIQUE -# index_topic_users_on_user_id_and_topic_id (user_id,topic_id) UNIQUE +# index_topic_users_on_topic_id_and_notification_level (topic_id,notification_level) +# index_topic_users_on_topic_id_and_user_id (topic_id,user_id) UNIQUE +# index_topic_users_on_user_id_and_topic_id (user_id,topic_id) UNIQUE # diff --git a/app/models/user_option.rb b/app/models/user_option.rb index c19e327089f..87232465f5d 100644 --- a/app/models/user_option.rb +++ b/app/models/user_option.rb @@ -295,6 +295,7 @@ end # # Indexes # -# index_user_options_on_user_id (user_id) UNIQUE -# index_user_options_on_user_id_and_default_calendar (user_id,default_calendar) +# index_user_options_on_user_id (user_id) UNIQUE +# index_user_options_on_user_id_and_default_calendar (user_id,default_calendar) +# index_user_options_on_watched_precedence_over_muted (watched_precedence_over_muted) # diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index dfd31db3bee..b0cb9310a2e 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -268,19 +268,26 @@ class PostAlerter end def category_or_tag_muters(topic) + user_option_condition_sql_fragment = + if SiteSetting.watched_precedence_over_muted + "uo.watched_precedence_over_muted IS false" + else + "(uo.watched_precedence_over_muted IS NULL OR uo.watched_precedence_over_muted IS false)" + end + user_ids_sql = <<~SQL - SELECT user_id FROM category_users WHERE category_id = #{topic.category_id.to_i} AND notification_level = #{CategoryUser.notification_levels[:muted]} - UNION - SELECT user_id FROM tag_users tu JOIN topic_tags tt ON tt.tag_id = tu.tag_id AND tt.topic_id = #{topic.id} AND tu.notification_level = #{TagUser.notification_levels[:muted]} - EXCEPT - SELECT user_id FROM topic_users tus WHERE tus.topic_id = #{topic.id} AND tus.notification_level = #{TopicUser.notification_levels[:watching]} - SQL - User - .where("id IN (#{user_ids_sql})") - .joins("LEFT JOIN user_options ON user_options.user_id = users.id") - .where( - "user_options.watched_precedence_over_muted IS false OR (user_options.watched_precedence_over_muted IS NULL AND #{!SiteSetting.watched_precedence_over_muted})", - ) + SELECT uo.user_id FROM user_options uo + LEFT JOIN topic_users tus ON tus.user_id = uo.user_id AND tus.topic_id = #{topic.id} + LEFT JOIN category_users cu ON cu.user_id = uo.user_id AND cu.category_id = #{topic.category_id.to_i} + LEFT JOIN tag_users tu ON tu.user_id = uo.user_id + JOIN topic_tags tt ON tt.tag_id = tu.tag_id AND tt.topic_id = #{topic.id} + WHERE + (tus.id IS NULL OR tus.notification_level != #{TopicUser.notification_levels[:watching]}) + AND (cu.notification_level = #{CategoryUser.notification_levels[:muted]} OR tu.notification_level = #{TagUser.notification_levels[:muted]}) + AND #{user_option_condition_sql_fragment} + SQL + + User.where("id IN (#{user_ids_sql})") end def notify_first_post_watchers(post, user_ids, notified = nil) diff --git a/db/migrate/20230707031122_add_watched_precedence_over_muted_index_to_user_options.rb b/db/migrate/20230707031122_add_watched_precedence_over_muted_index_to_user_options.rb new file mode 100644 index 00000000000..91d32ac03cb --- /dev/null +++ b/db/migrate/20230707031122_add_watched_precedence_over_muted_index_to_user_options.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddWatchedPrecedenceOverMutedIndexToUserOptions < ActiveRecord::Migration[7.0] + def change + add_index :user_options, :watched_precedence_over_muted + end +end diff --git a/db/migrate/20230712011946_add_topic_id_notification_level_index_to_topic_users.rb b/db/migrate/20230712011946_add_topic_id_notification_level_index_to_topic_users.rb new file mode 100644 index 00000000000..4b7aa7a1e58 --- /dev/null +++ b/db/migrate/20230712011946_add_topic_id_notification_level_index_to_topic_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +# +class AddTopicIdNotificationLevelIndexToTopicUsers < ActiveRecord::Migration[7.0] + def change + add_index :topic_users, %i[topic_id notification_level] + end +end diff --git a/db/migrate/20230712013248_add_category_id_notification_level_index_to_category_users.rb b/db/migrate/20230712013248_add_category_id_notification_level_index_to_category_users.rb new file mode 100644 index 00000000000..164ab11743f --- /dev/null +++ b/db/migrate/20230712013248_add_category_id_notification_level_index_to_category_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddCategoryIdNotificationLevelIndexToCategoryUsers < ActiveRecord::Migration[7.0] + def change + add_index :category_users, %i[category_id notification_level] + end +end