【问题标题】:Rails: how to load 2 models via join?Rails:如何通过加入加载 2 个模型?
【发布时间】:2009-08-23 20:34:58
【问题描述】:

我是 Rails 新手,希望能帮助我优化我的数据库使用。

有没有办法通过一个数据库查询加载两个相互关联的模型?

我有两个模型 Person 和 Image:

class Person < ActiveRecord::Base
  has_many :images
end

class Image < ActiveRecord::Base
  belongs_to :person
end

我想使用 join 命令在一次访问数据库的过程中加载一组人员及其相关图像。例如,在 SQL 中,我可以使用以下查询加载我需要的所有数据:

select * from people join images on people.id = images.person_id where people.id in (2, 3) order by timestamp;

所以我希望这个 rails sn-p 能满足我的需要:

>> people_and_images = Person.find(:all, :conditions => ["people.id in (?)", "2, 3"], :joins => :images, :order => :timestamp)

此代码执行我期望的 SQL 语句并加载我需要的 Person 实例。但是,我发现访问人的图像会导致额外的 SQL 查询。

>> people_and_images[0].images


Image Load (0.004889)   SELECT * FROM `images` WHERE (`images`.person_id = 2)

在调用 find() 时使用 :include 选项确实会加载两个模型,但是通过与 JOIN 一起执行它会花费我额外的 SELECT。

我想在 Rails 中做我可以在 SQL 中做的事情,即通过一个查询获取我需要的所有数据。

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 您找到解决方案了吗?非常感谢任何帮助

标签: ruby-on-rails join


【解决方案1】:

你想用:include点赞

Person.find(:all, :conditions => ["people.id in (?)", "2, 3"], :include => :images, :order => :timestamp)

查看find documentation for 了解更多详情

【讨论】:

  • 嗨 Rob,我可能不太理解 :include,但正如帖子中所述,我通过查询分析器看到 :include 仍然会导致执行额外的 SELECT。因此,在原始 SQL 中,我执行一个查询。在 Rails 中,我似乎需要两个。
  • 不,包含应该在一个查询中完成。可能这是解释如何完成的更好的链接。 api.rubyonrails.org/classes/ActiveRecord/Associations/…你确定这是第二个查询不是来自别的东西吗?
  • 也许我被我的日志误导了。我正在使用查询分析器插件 (agilewebdevelopment.com/plugins/query_analyzer) 来查看在我的数据库上执行了哪些 sql 语句。这个调用: people_and_images = Person.find(:all, :conditions => ["people.id in (?)", "2, 3"], :joins => :images, :order => :timestamp, :include => :images) 导致两个 select 语句被执行(见下一条评论):
  • 人员负载 (0.005105) SELECT people.* FROM people INNER JOIN images ON images.person_id = people.id WHERE (people.id in ('2, 3')) ORDER BY timestamp Image Load (0.002779) SELECT images.* FROM images WHERE (images.person_id IN (2))
【解决方案2】:

您可以使用 :include 来预先加载关联,实际上它确实调用了 2 个查询,而不是 :joins; 的情况。第一个查询是加载主模型,第二个是加载关联模型。这对于解决臭名昭著的 N+1 查询问题特别有帮助,如果您不使用 :include 并且 :joins 不会预先加载关联,您将面临这个问题。

使用 :joins 和 :include 的区别在于 :include 多查询 1 个,但不使用 :include 的区别会大很多。

您可以在这里查看:http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

【讨论】:

  • 嗨 Staelen,我认为我的帖子让人们感到困惑。我的问题确实是:如果我可以通过一个 SQL 连接查询获取我需要的所有数据,为什么我不能在 Rails 中做同样的事情?我并不是真的在问如何填充这 2 个模型。相反,我在问为什么我不能用一个调用来填充这两个模型,它可以为我提供我需要的所有数据?在上面的示例中,带有 :joins 选项的 find() 命令转换为 sql 连接查询,该查询实际上获取填充 Person 和 Image 模型所需的所有数据。然而,rails 最终只填充了 Person 模型,这是低效的。
  • 我认为这个博客可以解释更多内容,让您更好地了解正在发生的事情:akitaonrails.com/2008/5/26/… 希望对您有所帮助 =)
  • 查看优化的渴望加载部分 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多