急切加载与加入获取相同吗?

Posted

技术标签:

【中文标题】急切加载与加入获取相同吗?【英文标题】:Is eager loading same as join fetch? 【发布时间】:2011-03-16 08:22:27 【问题描述】:

eager fetch 和 join fetch 一样吗?

我的意思是急切地获取一个有多个关系是否会触发 2 个查询或单个连接查询?

rails 活动记录如何实现关联的连接获取,因为它不知道第一手的表的元数据(我的意思是表中的列)?比如说我有

人 - id、姓名 事物 - id、person_id、名称

人与事物是一对多的关系。那么它如何生成具有所有列别名的查询,即使当我对人员进行连接提取时它不知道它?

【问题讨论】:

和“includes”类似于 jpa/hibernate 中的 join fetch Hibernate 既有 Eager fetch 也有 join fetch。它们之间有区别吗? (自休眠以来已经有一段时间了,但我认为)“eager fetch”意味着您告诉 Hibernate“立即将对象实例加载到内存中”,“join fetch”是一种快捷方式(只是像“包含”),它允许您在单个查询/句子中定义您希望在返回时也加入和获取多级关联。在 ActiveRecord 中,“eager join fetch”将是:'People.includes(:things).all'('all' 现在将它们拉入内存,而不是等待它们被迭代。) 【参考方案1】:

答案未被接受,因此我会尽量按照我的理解回答您的问题:

“它如何知道表中所有可用的字段?”

它对继承自 ActiveRecord::Base 的每个类执行 SQL 查询。如果类是'Dog',它将执行查询以查找表'dogs' 的列名。在生产模式下,每次运行服务器时它应该只做一次这个查询——在开发模式下它会做很多。查询会因您使用的数据库而异,而且通常是一个昂贵的查询。

“如果我在一个表和关联表中的列具有相同的名称,它如何解决这个问题?”

如果您正在执行连接,它会使用表名作为前缀生成 sql 以避免歧义。其实如果你在Rails中做join,想为name添加条件(使用自定义SQL),但是主表和join表都有name列,你需要在sql中指定表名。 (例如 Human.join(:pets).where("humans.name = 'John'"))

“我的意思是急切地获取一个有多个关系会触发 2 个查询还是单个连接查询?”

不同的 Rails 版本是不同的。我认为早期版本始终只进行一次连接查询。更高版本有时会执行多个查询,有时会执行单个连接查询,这是基于单个连接查询并不总是与多个查询一样高效的认识。我不确定它用来决定的确切逻辑。最近,在 Rails 3 中,我看到我当前的代码库中发生了多个查询——但也许它有时也会进行连接,我不确定。

【讨论】:

【参考方案2】:

它通过一种反射来识别列。 Ruby 非常灵活,允许您构建将在运行时使用/定义的功能,无需提前声明。它通过解释“belongs_to :person”并知道“person_id”是要关联的字段并且表将被称为“people”来学习关联的“person_id”列。

如果您执行 People.includes(:things) 那么它将生成 2 个查询,1 个获取人员,第二个获取与存在的人员相关的事物。

http://guides.rubyonrails.org/active_record_querying.html

【讨论】:

它可以知道类中的字段,但我要问的是它如何知道表中可用的所有字段。假设我在表和关联表中的列名称相同,它如何解决这个问题?它怎么知道一开始就有歧义 它知道类中的字段 yes(就像 java 一样),但它也使用反射来询问类后面的数据模型(如果它继承自 ActiveRecord::Base)并存储该列数据在类中的另一个数据结构中,现在称为“arel_table”。 Arel 是实际编译查询的关系代数包(有点像 HQL,因为您熟悉 Hibernate)。对于歧义,这是解决的,因为幕后的每个“arel_table”都会跟踪它自己的范围并根据您定义的关系解析其中的关系(has_many has_one ...)

以上是关于急切加载与加入获取相同吗?的主要内容,如果未能解决你的问题,请参考以下文章

Rails 急切加载

Laravel Eager Loading - 总是好的?

我可以同时使用急切和延迟加载吗?

使用相同类型的多个关系改进急切加载

EF急切加载和延迟加载的区别?

LINQ中的First()会导致急切或延迟加载吗?