2

我们有一个设置了 has_one 关联的模型:

class User
  has_one :shirt

class Shirt
  belongs_to :user

目前我们可以.includes(:shirt)在检索有限的用户数组时添加,它将按预期执行两个 SQL 查询。

我们的问题是加载页面的查询是这样做的:

SELECT "shirt".* FROM "shirts" WHERE "shirt"."user_id" IN (2147521, 2147522 ... )

例如,在检索 50 个用户和衬衫时,这对我们来说性能不是很好。我们的用户和衬衫表很大。我们注意到通过强制 Rails 使用 INNER JOIN 来代替执行以下操作可以大大提高速度:

User.where( ... ).joins(:shirts).includes(:shirts).limit(50)

不幸的是,这只返回有衬衫的用户。我们需要能够返回有限的用户数组,无论他们是否有相关的衬衫。

有没有办法强制 Rails 使用 LEFT OUTER JOIN 而不是默认的两个查询方法来预先加载关联的对象?

编辑

通过添加一个where返回 true 的子句,无论关联对象上的值是否为空。至少在 Postgres 上,如果没有关联的对象,它似乎并不介意。

User.where( ... ).includes(:shirt).where("shirts.created_at IS NULL OR shirts.created_at IS NOT NULL")

这解决了问题,但它并不理想,有没有办法使用 LEFT OUTER JOIN 代替默认的两个查询方法?

4

3 回答 3

2

正如这篇文章中所解释的,在大多数情况下,2 查询方法被认为更快(尽管对于您所拥有的一对一关系来说不一定如此)。如果你想强制 Rails 使用 LEFT OUTER JOIN,你可以通过在关联表上添加一个无意义的过滤器来做到这一点:

User.where( ... ).
     includes(:shirts).
     where("shirts.id IS NULL OR shirts.id = shirts.id").
     limit(50)
于 2012-12-17T18:01:30.827 回答
1

如果你有一对一的关联,就像你上面的例子一样,你可以使用eager_load这样的方法 : User.eager_load(:shirt),它将使用LEFT OUTER JOIN,所以你只能使用user.shirt1 个查询,但我不确定它是否是新的轨道 4 与否。

于 2014-09-10T10:12:49.507 回答
0

应用于 Rails4:

User.where( ... ).includes(:shirts).references(:shirts)

或者

User.where( ... ).eager_load(:shirts)

将强制进行LEFT OUTER JOIN相当单独的查询

于 2015-03-02T19:14:06.157 回答