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.
This commit is contained in:
Sam 2021-04-21 10:42:07 +10:00 committed by GitHub
parent 3c0164f369
commit 5c49009c6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 19 deletions

View File

@ -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

View File

@ -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)
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
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)
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,