Rails ActiveAdmin 消除对属于另一个模型的自定义属性的 n+1 查询

问题描述 投票:0回答:2

我使用activeadmin来显示分支模型记录,分支模型有很多分支电话,我想在activeadmin分支模型屏幕上显示为此分支创建的第一个分支电话作为额外的自定义属性,所以我这样写

    show do
    attributes_table do
      row :id
      row :manager_name
      row :manager_email
      row :phone_number do |branch|
        branch&.branch_phones&.order(created_at: :asc)&.first&.phone_number
      end
    end
  end

  index do
    column :id
    column :manager_name
    column :manager_email
    column :phone_number do |branch|
      branch&.branch_phones&.order(created_at: :asc)&.first&.phone_number
    end
    actions
  end

该代码的问题在于,它会导致我执行 n+1 次查询,每次代码获取分支时,它都会在其中创建一个额外的查询以获取分支的分支电话,这会在调用分支时产生类似的结果activeadmin 上的模型屏幕

Processing by Admin::BranchesController#index as HTML
  Parameters: {"subdomain"=>""}
  AdminUser Load (0.8ms)  SELECT  "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = $1 ORDER BY "admin_users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering /usr/local/bundle/gems/activeadmin-2.7.0views/active_admin/resource/index.html.arb
   (0.6ms)  SELECT COUNT(*) FROM (SELECT  1 AS one FROM "branches" LIMIT $1 OFFSET $2) subquery_for_count  [["LIMIT", 30], ["OFFSET", 0]]
  CACHE  (0.1ms)  SELECT COUNT(*) FROM (SELECT  1 AS one FROM "branches" LIMIT $1 OFFSET $2) subquery_for_count  [["LIMIT", 30], ["OFFSET", 0]]
   (0.4ms)  SELECT COUNT(*) FROM "branches"
  CACHE  (0.0ms)  SELECT COUNT(*) FROM (SELECT  1 AS one FROM "branches" LIMIT $1 OFFSET $2) subquery_for_count  [["LIMIT", 30], ["OFFSET", 0]]
  Branch Load (0.5ms)  SELECT  "branches".* FROM "branches" ORDER BY "branches"."id" desc LIMIT $1 OFFSET $2  [["LIMIT", 30], ["OFFSET", 0]]
  Store Load (0.6ms)  SELECT "stores".* FROM "stores" WHERE "stores"."id" IN ($1, $2, $3)  [["id", 21], ["id", 1], ["id", 2]]
  BranchPhone Load (0.4ms)  SELECT "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)  [["branch_id", 25], ["branch_id", 24], ["branch_id", 22], ["branch_id", 20], ["branch_id", 19], ["branch_id", 14], ["branch_id", 11], ["branch_id", 4], ["branch_id", 3], ["branch_id", 2], ["branch_id", 1]]
  BranchPhone Load (0.7ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 25], ["LIMIT", 1]]
  BranchPhone Load (0.5ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 24], ["LIMIT", 1]]
  BranchPhone Load (0.3ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 22], ["LIMIT", 1]]
  BranchPhone Load (0.6ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 20], ["LIMIT", 1]]
  BranchPhone Load (0.3ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 19], ["LIMIT", 1]]
  BranchPhone Load (0.3ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 14], ["LIMIT", 1]]
  BranchPhone Load (0.2ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 11], ["LIMIT", 1]]
  BranchPhone Load (0.2ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 4], ["LIMIT", 1]]
  BranchPhone Load (0.3ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 3], ["LIMIT", 1]]
  BranchPhone Load (0.2ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 2], ["LIMIT", 1]]
  BranchPhone Load (0.2ms)  SELECT  "branch_phones".* FROM "branch_phones" WHERE "branch_phones"."branch_id" = $1 ORDER BY "branch_phones"."created_at" ASC LIMIT $2  [["branch_id", 1], ["LIMIT", 1]]
  Rendered /usr/local/bundle/gems/activeadmin-2.7.0views/active_admin/resource/index.html.arb (219.4ms)
Completed 200 OK in 258ms (Views: 208.7ms | ActiveRecord: 23.2ms)

那么,有什么解决方案可以消除分行电话的n+1查询吗? 知道我试图使用这样的控制器操作来消除它 enter image description here

但分行电话N+1查询仍未解决

enter image description here

ruby-on-rails database postgresql performance activeadmin
2个回答
1
投票

您收到 (N+1) 次查询,因为您正在订购

branch_phones
。默认情况下,Rails 按同意顺序返回记录。您不必再次订购。

我相信你有如下的联想:

# app/models/branch.rb

class Branch < ApplicationRecord
  has_many :branch_phones
end
# app/models/branch_phone.rb

class BranchPhone < ApplicationRecord
  belongs_to :branch
end

请将此行添加到您的

app/admin/brach.rb
文件中。

# app/admin/brach.rb

controller do
  def scoped_collection
    super.includes(:branch_phones)
  end
end

index do
  column :id
  column :manager_name
  column :manager_email
  column :phone_number do |branch|
    branch.branch_phones.first&.phone_number
  end

  actions
end

1
投票

现在 includes 方法在 ActiveAdmin 中可用。您需要做的就是将其添加到所需的管理文件中。

ActiveAdmin.register Branch do
  includes :branch_phones

  index do
    column :id
    column :manager_name
    column :manager_email
    column :phone_number do |branch|
      branch&.branch_phones&.order(created_at: :asc)&.first&.phone_number
    end
    actions
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.