PERF: properly preload emails to speed up user exports (#12778)

PERF: properly preload emails to speed up user exports (#12778)

scopes are incredibly annoying to preload, simply adding :user_emails is not enough.

Instead of relying on scopes simply iterate through user_emails which is properly preloaded.

This removes 2 * N+1 when generating user reports.

diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 5dc1710..a880acf 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -443,7 +443,7 @@ class Admin::UsersController < Admin::AdminController
 
     begin
       sso = DiscourseSingleSignOn.parse("sso=#{params[:sso]}&sig=#{params[:sig]}", secure_session: secure_session)
-    rescue DiscourseSingleSignOn::ParseError => e
+    rescue DiscourseSingleSignOn::ParseError
       return render json: failed_json.merge(message: I18n.t("discourse_connect.login_error")), status: 422
     end
 
diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb
index 3141952..4ff6d1a 100644
--- a/app/jobs/regular/export_csv_file.rb
+++ b/app/jobs/regular/export_csv_file.rb
@@ -113,24 +113,21 @@ module Jobs
         condition = { trust_level: trust_level }
       end
 
+      includes = [:user_profile, :user_stat, :groups, :user_emails]
       if SiteSetting.enable_discourse_connect
-        # SSO enabled
-        User.where(condition).includes(:user_profile, :user_stat, :user_emails, :single_sign_on_record, :groups).find_each do |user|
-          user_info_array = get_base_user_array(user)
+        includes << [:single_sign_on_record]
+      end
+
+      User.where(condition).includes(*includes).find_each do |user|
+        user_info_array = get_base_user_array(user)
+        if SiteSetting.enable_discourse_connect
           user_info_array = add_single_sign_on(user, user_info_array)
-          user_info_array = add_custom_fields(user, user_info_array, user_field_ids)
-          user_info_array = add_group_names(user, user_info_array)
-          yield user_info_array
-        end
-      else
-        # SSO disabled
-        User.where(condition).includes(:user_profile, :user_stat, :user_emails, :groups).find_each do |user|
-          user_info_array = get_base_user_array(user)
-          user_info_array = add_custom_fields(user, user_info_array, user_field_ids)
-          user_info_array = add_group_names(user, user_info_array)
-          yield user_info_array
         end
+        user_info_array = add_custom_fields(user, user_info_array, user_field_ids)
+        user_info_array = add_group_names(user, user_info_array)
+        yield user_info_array
       end
+
     end
 
     def staff_action_export
@@ -254,11 +251,23 @@ module Jobs
     end
 
     def get_base_user_array(user)
+      # preloading scopes is hard, do this by hand
+      secondary_emails = []
+      primary_email = nil
+
+      user.user_emails.each do |user_email|
+        if user_email.primary?
+          primary_email = user_email.email
+        else
+          secondary_emails << user_email.email
+        end
+      end
+
       [
         user.id,
         escape_comma(user.name),
         user.username,
-        user.email,
+        primary_email,
         escape_comma(user.title),
         user.created_at,
         user.last_seen_at,
@@ -274,7 +283,7 @@ module Jobs
         user.moderator,
         user.ip_address,
         user.staged,
-        user.secondary_emails.join(";"),
+        secondary_emails.join(";"),
         user.user_stat.topics_entered,
         user.user_stat.posts_read_count,
         user.user_stat.time_read,

GitHub sha: 5c49009c

1 Like

This commit appears in #12778 which was approved by lis2. It was merged by SamSaffron.