轨道预先加载和where子句(Rails Eager Loading and where claus

2019-07-22 03:02发布

我渴望加载与其关联的模型对象:

user= User.includes(:posts).find(1)

但随后在代码中的某些点,我想这样做:

user.posts.where(:topic => "x")

但是,这只是再次重新运行查询。 所以不是我想我应该这样做:

user.posts.select{|post| post.topic == "x" }

这不会重新运行查询。 但我有几个问题。

首先,这是做的正确方法?

其次,我有点困惑什么选择呢在这种情况下。 因为,即使我没有使用过,当我运行最后一行包括功能,它运行查询,然后后,如果我再次运行它,它不..所以是有某种形式的缓存所涉及的第一次? 因为当我使用WHERE子句运行查询每一次。

谢谢。

Answer 1:

select是在可枚举一个Ruby方法。 第一次运行

user.posts.select{|post| post.topic == "x" }

所有Post的情况下, user:posts协会将被从数据库到内存中加载; 具体到一个ActiveRecord集合对象。 select ,然后调用这个收集,过滤掉所有Post与集合中的实例:topic属性比其他任何"x"

运行上面的行第二次不会再查询数据库,因为你已经加载的posts到内存中。


当你做一个includes像下面

user= User.includes(:posts).find(1)

它要急切负载:posts对于每个关系User实例返回(在这种情况下,单个User ,其中:id1 )。 您现在都Post加载到内存中的实例如上一节所述。

如果你再这样做

user.posts.where(:topic => "x")

现在你告诉轨运行针对一个新的查询Post ,这次发现的所有Post实例,其中:topic"x"和其中:user_id:id的的userwhere不工作就像一个内存AREL集合的“过滤器”。


  • 如果你想避免另一个查询坏, select是滤除内存结果集的好方法。
  • 您可以运行基准测试来发现这是更快:
    1. 查询数据库和重新建另一个AREL收集到内存
    2. 遍历存储器内enumberable和用Ruby运行的过滤器
  • 如果你从来没有需要所有相关:postsuser ,你可以很容易地包括在这个原始查询

     user.includes(:posts).where("posts.topic = ?", 'x') 


文章来源: Rails Eager Loading and where clause