这有什么区别:
User.includes(:sites).where("sites.name = 'test'").references(:sites)
还有这个:
User.joins(:sites).where(sites: { name: "test"} )
对于使用其中一种方法而不是另一种方法,是否存在普遍的共识?
这有什么区别:
User.includes(:sites).where("sites.name = 'test'").references(:sites)
还有这个:
User.joins(:sites).where(sites: { name: "test"} )
对于使用其中一种方法而不是另一种方法,是否存在普遍的共识?
他们做的事情完全不同。
.joins(:sites)
INNER JOIN
在应用 where 子句之前,向关系中添加一个,将结果限制为至少具有一个站点的用户。不会选择连接表之外的任何列(除非您手动选择)。当您只想使用连接过滤结果而不关心相关表中的数据或
.select
选择聚合时,请使用它。当您访问关联时,它不会阻止 N+1 查询:
.includes
以“智能”方式避免 N+1 查询。它被过度使用,通常你最好只考虑如何使用数据并直接使用它委托的方法。它将尝试执行
.preload
两个查询,第一个查询将从用户表中选择数据,第二个查询将sites
在首次访问集合的任何成员上的关联时从表中选择数据。这将避免加载数据,除非它实际被使用,同时防止对关联的每个成员进行 N+1 查询。但是,如果查询通过 where 子句引用站点表,
.preload
则它不会起作用,因为它实际上并没有连接任何东西。.includes
实际上足够智能,可以在大多数情况下检测到这一点,并将使用.eager_load
外连接在单个查询中加载所有内容。.references
明确告诉.includes
使用.eager_load
并在该示例中将阻止在查询未连接时发生的数据库驱动程序sites
。但是,如果您只是传递一个哈希值,
.where
而不是为了示例而用 SQL 字符串主动破坏它,那么它就可以正常工作:如果您认为可以直接省去中间人而不必如此优柔寡断,那就更加没有意义了。
我想,
.references
如果您以编程方式构建查询并希望使用延迟加载特性,.includes
但同时避免引用错误(这种情况需要很多想象力),它仍然可以填补一个非常小众的角色。但总的来说 - YAGNI。