簡體   English   中英

rails 通過連接表預先加載 has_many

[英]rails eager load has_many through join table

我的開發環境是 Rails 4.1 和 postgresql

我有 3 個具有 has_many 關系的模型:

class Item < ActiveRecord::Base
  has_many :item_parts
  has_many :parts, through: :item_parts
end

class Part < ActiveRecord::Base
  has_many :item_parts
  has_many :items, through: :item_parts
end

class ItemPart < ActiveRecord::Base
  belongs_to :item
  belongs_to :part 
end

item_parts 連接表有一個 unit_count 屬性來跟蹤項目包含的部分數量。

當我在視圖中遍歷特定項目的所有部分時,我還需要從連接表中獲取 unit_count 值。

這給了我 n+1 查詢問題。

我試圖急切加載連接表:

item.parts.includes(:item_parts)

ItemPart Load (0.5ms)  SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" IN (24, 12, 3, 26)

但是當我這樣做之后:

part.item_parts.where(item_id: item.id).first.unit_count

我對每個部分都進行了以下 sql 查詢; 急切加載不起作用

ItemPart Load (0.5ms)  SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" = $1 AND "item_parts"."item_id" = $2  [["part_id", 24], ["item_id", 18]]

有什么建議?

按照此鏈接,我找到了適用於我的案例的解決方案: Rails Eager Loading 和 where 子句

我不知道 Active Record 查詢方法:選擇( http://apidock.com/rails/v4.1.8/ActiveRecord/QueryMethods/select

似乎我無法急切加載連接表,因為在包含 item_parts 之后,我在項目部件的迭代過程中使用了 where 子句。

似乎 where 子句在迭代期間每次使用時都會對數據庫進行新查詢。

相反, select 方法不會每次都命中數據庫,而是在加載到內存中的 Active Record 集合上工作。

所以我改變了這個:

item.parts.includes(:item_parts)
part.item_parts.where(item_id: item.id).first.unit_count

有了這個:

item.parts.includes(:item_parts)
part.item_parts.select{|item_part| item_part.item_id == item.id}.first.unit_count

然后我有一個查詢來加載 item_parts:

ItemPart Load (0.5ms)  SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" IN (24, 12, 3, 26)

我希望這是因為您正在使用“計數”方法,根據:

http://dev.mensfeld.pl/2014/09/activerecord-count-vs-length-vs-size-and-what-will-happen-if-you-use-it-the-way-you-shouldnt/

“在對象生命周期內部不存儲,這意味着,每次我們調用此方法時,都會再次執行 SQL 查詢”

嘗試改用.length.size方法。

注:(引用文章)

長度 – 集合.長度

  • 返回集合的長度而不執行額外的查詢……只要集合被加載
  • 當我們延遲加載集合時,length 會將整個集合加載到內存中,然后返回它的長度
  • 使用不當可能會占用您所有的內存
  • 擁有急切加載的集合時真的很快

大小 - 集合.大小

  • 結合了之前兩種方法的能力;
  • 如果加載了集合,將計算它的元素(沒有額外的查詢)
  • 如果未加載集合,將執行附加查詢

再次查看后,我不確定您為什么要將計數添加到連接表中。

@items = Item.includes(:parts)

@items.each do |item|
   parts_count_per_item = item.parts.size
end

或者

@parts = Part.includes(:items)

@parts.each do |part|
   items_count_per_part = part.items.size
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM