Ruby on rails 在一个归属关系上,急切的加载有很多

Ruby on rails 在一个归属关系上,急切的加载有很多,ruby-on-rails,rails-activerecord,Ruby On Rails,Rails Activerecord,我有一些这样的模型: class Image < ActiveRecord::Base has_many :tag_groups end class TagGroup < ActiveRecord::Base belongs_to :image has_many :tag_group_members has_many :tags, through: :tag_group_members end class TagGroupMember < ActiveRec

我有一些这样的模型:

class Image < ActiveRecord::Base
  has_many :tag_groups
end

class TagGroup < ActiveRecord::Base
  belongs_to :image
  has_many :tag_group_members
  has_many :tags, through: :tag_group_members
end

class TagGroupMember < ActiveRecord::Base
  belongs_to :tag_group
  belongs_to :tag
end

class Tag
  has_many :tag_group_members
  has_many :tag_groups, through: :tag_group_members
end
然而,通过迭代(
@image.tag_groups.map{g|g.tags.map{t|t.name}}
),我们发现Rails正在进行大量的SQL查询:

TagGroup Load (0.8ms)  SELECT "tag_groups".* FROM "tag_groups" WHERE "tag_groups"."image_id" IN (1)
  Tag Exists (0.3ms)  SELECT  1 AS one FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1 LIMIT 1  [["tag_group_id", 1]]
  Tag Load (0.3ms)  SELECT "tags".* FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1  [["tag_group_id", 1]]
  Tag Exists (0.3ms)  SELECT  1 AS one FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1 LIMIT 1  [["tag_group_id", 3]]
  Tag Load (0.3ms)  SELECT "tags".* FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1  [["tag_group_id", 3]]
  Tag Exists (0.6ms)  SELECT  1 AS one FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1 LIMIT 1  [["tag_group_id", 4]]
  Tag Load (0.6ms)  SELECT "tags".* FROM "tags" INNER JOIN "tag_group_members" ON "tags"."id" = "tag_group_members"."tag_id" WHERE "tag_group_members"."tag_group_id" = $1  [["tag_group_id", 4]]
现在,似乎只需三个查询就可以相当轻松地处理此问题:

SELECT images.* FROM images WHERE images.id = $1
然后:

SELECT tag_groups.* FROM tag_groups WHERE tag_groups.image_id = $1
最后:

SELECT tags.*, tag_groups.id AS tag_group_id FROM tags
INNER JOIN tag_group_members ON tag_group_members.tag_id = tags.id
INNER JOIN tag_groups ON tag_groups.id = tag_group_members.tag_group_id
WHERE tag_groups.image_id = $1 -- alternatively, where tag_groups.id IN (results from the previous query)
然后,您可以简单地将标记关联到内存中适当的标记组,这应该比查询每个标记组的数据库快得多

有没有办法让Rails在不进行那么多连接的情况下加载这个关联

只是:

@image = Image.includes(tag_groups: {tag_group_members: :tags}).find(param[:id])
Image
第一次调用
include
,返回
ActiveRecord::Relation
,然后可以调用
find


这就可以了。

您甚至不需要您提到的第二个查询,因为您已经有了
标记组。在您的加入查询中,image\u id

i = Image.find params[:id]
tgs = i.tag_groups.joins(:tags)
更新 有趣的是,我没有意识到,
连接
也没有在内存中加载关联,似乎您需要在上述代码中添加一个
.includes(:tags)
,以防止运行任何其他查询

此外,这也完成了同样的事情,但只需一步:

i = Image.joins(tag_groups: :tags).includes(tag_groups: :tags).find 1

如果你问我认为你是什么,你需要Image.find(params[:id])。includes(:tag_groups=>:tags)或类似的东西。不,这仍然会做同样多的标记加载查询。事实上,现在它添加了一组“Tag Exists”查询
从“tags”内部连接“Tag\u group\u members”中选择1作为一个查询。“id”=“Tag\u group\u members”。“Tag\u id”其中的“Tag\u group\u members”。“Tag\u group\u id”=“1美元限制1
i = Image.joins(tag_groups: :tags).includes(tag_groups: :tags).find 1