Skip to content
Snippets Groups Projects

Improve database response time for listing user activity

Merged Andreas Brandl requested to merge 40525-listing-user-activity-timeouts into master
All threads resolved!
Files
13
@@ -12,6 +12,8 @@ class UserRecentEventsFinder
attr_reader :current_user, :target_user, :params
LIMIT = 20
def initialize(current_user, target_user, params = {})
@current_user = current_user
@target_user = target_user
@@ -19,15 +21,58 @@ def initialize(current_user, target_user, params = {})
end
def execute
target_user
.recent_events
.merge(projects_for_current_user)
.references(:project)
recent_events(params[:offset] || 0)
.joins(:project)
.with_associations
.limit_recent(20, params[:offset])
.limit_recent(LIMIT, params[:offset])
end
private
def recent_events(offset)
sql = if Gitlab::Database.join_lateral_supported?
lateral_join(offset)
else
normal_join
end
# Workaround for https://github.com/rails/rails/issues/24193
Event.from([Arel.sql(sql)])
end
def lateral_join(offset)
lateral = target_events
.where('events.project_id = projects_for_lateral.id')
.order('id DESC')
.limit(LIMIT + Integer(offset)) # Consider this is used in LATERAL JOIN and we paginate/offset the outer relation
.to_sql
"(#{projects}) AS projects_for_lateral JOIN LATERAL (#{lateral}) AS #{Event.table_name} ON true"
end
def projects_for_current_user
ProjectsFinder.new(current_user: current_user).execute
def normal_join
"(#{projects}) AS projects_for_join JOIN (#{target_events.to_sql}) AS #{Event.table_name} ON #{Event.table_name}.project_id = projects_for_join.id"
end
def target_events
Event.where(author: target_user)
end
def projects
# Compile a list of projects `current_user` interacted with
# and `target_user` is allowed to see.
authorized = target_user
.project_interactions
.joins(:project_authorizations)
.where(project_authorizations: { user: current_user })
.select(:id)
visible = target_user
.project_interactions
.where(visibility_level: [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC])
.select(:id)
Gitlab::SQL::Union.new([authorized, visible]).to_sql
end
end
Loading