Fix performances of profile directory (#26842)

shrike
Claire 2023-09-07 18:55:25 +02:00 committed by GitHub
parent 858ad1f363
commit 81caafbe84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 7 deletions

View File

@ -125,7 +125,7 @@ class Account < ApplicationRecord
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) } scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) }
scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) } scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).left_outer_joins(:account_stat) } scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) } scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) }
scope :by_recent_status, -> { order(Arel.sql('account_stats.last_status_at DESC NULLS LAST')) } scope :by_recent_status, -> { order(Arel.sql('account_stats.last_status_at DESC NULLS LAST')) }
scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) } scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) }

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddIndexAccountStatsOnLastStatusAtAndAccountId < ActiveRecord::Migration[7.0]
disable_ddl_transaction!
def change
add_index :account_stats, [:last_status_at, :account_id], order: { last_status_at: 'DESC NULLS LAST' }, algorithm: :concurrently
end
end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_09_04_134623) do ActiveRecord::Schema[7.0].define(version: 2023_09_07_150100) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -99,6 +99,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_04_134623) do
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.datetime "last_status_at", precision: nil t.datetime "last_status_at", precision: nil
t.index ["account_id"], name: "index_account_stats_on_account_id", unique: true t.index ["account_id"], name: "index_account_stats_on_account_id", unique: true
t.index ["last_status_at", "account_id"], name: "index_account_stats_on_last_status_at_and_account_id", order: { last_status_at: "DESC NULLS LAST" }
end end
create_table "account_statuses_cleanup_policies", force: :cascade do |t| create_table "account_statuses_cleanup_policies", force: :cascade do |t|

View File

@ -15,12 +15,13 @@ describe Api::V1::DirectoriesController do
describe 'GET #show' do describe 'GET #show' do
context 'with no params' do context 'with no params' do
before do before do
_local_unconfirmed_account = Fabricate( local_unconfirmed_account = Fabricate(
:account, :account,
domain: nil, domain: nil,
user: Fabricate(:user, confirmed_at: nil, approved: true), user: Fabricate(:user, confirmed_at: nil, approved: true),
username: 'local_unconfirmed' username: 'local_unconfirmed'
) )
local_unconfirmed_account.create_account_stat!
local_unapproved_account = Fabricate( local_unapproved_account = Fabricate(
:account, :account,
@ -28,15 +29,17 @@ describe Api::V1::DirectoriesController do
user: Fabricate(:user, confirmed_at: 10.days.ago), user: Fabricate(:user, confirmed_at: 10.days.ago),
username: 'local_unapproved' username: 'local_unapproved'
) )
local_unapproved_account.create_account_stat!
local_unapproved_account.user.update(approved: false) local_unapproved_account.user.update(approved: false)
_local_undiscoverable_account = Fabricate( local_undiscoverable_account = Fabricate(
:account, :account,
domain: nil, domain: nil,
user: Fabricate(:user, confirmed_at: 10.days.ago, approved: true), user: Fabricate(:user, confirmed_at: 10.days.ago, approved: true),
discoverable: false, discoverable: false,
username: 'local_undiscoverable' username: 'local_undiscoverable'
) )
local_undiscoverable_account.create_account_stat!
excluded_from_timeline_account = Fabricate( excluded_from_timeline_account = Fabricate(
:account, :account,
@ -44,14 +47,16 @@ describe Api::V1::DirectoriesController do
discoverable: true, discoverable: true,
username: 'remote_excluded_from_timeline' username: 'remote_excluded_from_timeline'
) )
excluded_from_timeline_account.create_account_stat!
Fabricate(:block, account: user.account, target_account: excluded_from_timeline_account) Fabricate(:block, account: user.account, target_account: excluded_from_timeline_account)
_domain_blocked_account = Fabricate( domain_blocked_account = Fabricate(
:account, :account,
domain: 'test.example', domain: 'test.example',
discoverable: true, discoverable: true,
username: 'remote_domain_blocked' username: 'remote_domain_blocked'
) )
domain_blocked_account.create_account_stat!
Fabricate(:account_domain_block, account: user.account, domain: 'test.example') Fabricate(:account_domain_block, account: user.account, domain: 'test.example')
end end
@ -63,6 +68,7 @@ describe Api::V1::DirectoriesController do
discoverable: true, discoverable: true,
username: 'local_discoverable' username: 'local_discoverable'
) )
local_discoverable_account.create_account_stat!
eligible_remote_account = Fabricate( eligible_remote_account = Fabricate(
:account, :account,
@ -70,6 +76,7 @@ describe Api::V1::DirectoriesController do
discoverable: true, discoverable: true,
username: 'eligible_remote' username: 'eligible_remote'
) )
eligible_remote_account.create_account_stat!
get :show get :show
@ -84,6 +91,8 @@ describe Api::V1::DirectoriesController do
user = Fabricate(:user, confirmed_at: 10.days.ago, approved: true) user = Fabricate(:user, confirmed_at: 10.days.ago, approved: true)
local_account = Fabricate(:account, domain: nil, user: user) local_account = Fabricate(:account, domain: nil, user: user)
remote_account = Fabricate(:account, domain: 'host.example') remote_account = Fabricate(:account, domain: 'host.example')
local_account.create_account_stat!
remote_account.create_account_stat!
get :show, params: { local: '1' } get :show, params: { local: '1' }
@ -110,9 +119,9 @@ describe Api::V1::DirectoriesController do
context 'when ordered by new' do context 'when ordered by new' do
it 'returns accounts in order of creation' do it 'returns accounts in order of creation' do
account_old = Fabricate(:account) account_old = Fabricate(:account_stat).account
travel_to 10.seconds.from_now travel_to 10.seconds.from_now
account_new = Fabricate(:account) account_new = Fabricate(:account_stat).account
get :show, params: { order: 'new' } get :show, params: { order: 'new' }