Rails 3 拒绝急切加载

发布于 2024-11-06 19:34:24 字数 1474 浏览 1 评论 0原文

我正在使用 Rails 3.0.7。

我有一些多对多和一些一对多关联无法立即加载。

我的关联是:

Person has_many :friends
Person has_many :locations through=> :location_histories
Location belongs_to :location_hour
Location_hour has_many :locations

在我的控制器中,我有以下内容:

@people = Person.includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))").limit(10).all

然后在我看来,我有:

<% @people.each do |person| %>
  <tr>
    <td><%= link_to person.name, person %></td>
    <td><%= link_to person.friends.collect {|s| [s.full_name]}.join(", "), person.friends.first %></td>
    <td><%= link_to person.locations.current.first.name, person.locations.current.first %></td>
  </tr>
<% end %>

locations.current 是一个范围,定义为:

scope :current, lambda {
  where("location_histories.current = ?", true)
}

这按预期工作,首先生成 2 个数据库调用:一个用于获取人员 ID 列表,然后是一个大型数据库调用,所有内容都正确连接。问题是,之后有 n 个数据库调用,大致如下:

SELECT 'friends'.* from 'friends' WHERE ('friends'.person_id = 12345)

因此,对于视图中循环的每次迭代。不用说这需要一段时间。

我认为 .all 会强制急切加载。有人知道这里发生了什么吗?
这在 ActiveRecord 上花费了超过 3 秒的时间。太长了。

我将非常感谢任何和所有的建议。

谢谢。

I'm working in Rails 3.0.7.

I have some many-to-many and some one-to-many associations that fail to eager load.

My associations are:

Person has_many :friends
Person has_many :locations through=> :location_histories
Location belongs_to :location_hour
Location_hour has_many :locations

In my controller I have the following:

@people = Person.includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))").limit(10).all

Then in my view I have:

<% @people.each do |person| %>
  <tr>
    <td><%= link_to person.name, person %></td>
    <td><%= link_to person.friends.collect {|s| [s.full_name]}.join(", "), person.friends.first %></td>
    <td><%= link_to person.locations.current.first.name, person.locations.current.first %></td>
  </tr>
<% end %>

locations.current is a scope defined as:

scope :current, lambda {
  where("location_histories.current = ?", true)
}

This works as expected and first generates 2 database calls: one to get a list of person ids and then a big database call where everything is properly joined. THE PROBLEM is that after that there are n database calls along the lines of:

SELECT 'friends'.* from 'friends' WHERE ('friends'.person_id = 12345)

So for each iteration of the loop in the view. Needless to say this takes a while.

I thought that .all would force eager loading. Anyone have an idea what's going on here?
This spends over 3 seconds on ActiveRecord. Way too long.

I would greatly appreciate any and all suggestions.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遗失的美好 2024-11-13 19:34:24

好的。终于解决了。
我需要调用连接和包含。我还必须从连接中删除 :locations_current 关联。它试图制造一些混乱,

... LEFT OUTER JOIN `locations` ON `location_histories`.current = 1 ...  

这当然不是一个有效的关联。似乎“当前”子句被转移到联接中。

所以现在我有以下内容,它有效。

@people = Person.joins([[:locations=>:location_hour],:friends]).includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))")

总结:
1) 我需要同时使用 Joins 和 Includes 来急切加载和正确解释 .while() 条件
2)我需要在连接子句之外保留与条件(即:current_locations)的关联。

如果这对您来说是一个明显的错误,请纠正我。不过这似乎有效。这将 Active Record 时间缩短至不到 1 秒。

组合联接和包含是否常见?

谢谢!

OK. Finally Solved.
I needed to call both joins and includes. I've also had to remove the :locations_current association from the join. It was creating some chaos by attempting to

... LEFT OUTER JOIN `locations` ON `location_histories`.current = 1 ...  

Which of course is not a valid association. It seems that the 'current' clause was being carried over into the JOINS.

So now I have the following, which works.

@people = Person.joins([[:locations=>:location_hour],:friends]).includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))")

IN SUMMARY:
1) I needed to use both Joins and Includes for eager loading and proper interpretation of the .while() conditions
2) I needed to keep associations with conditions (i.e. :current_locations) out of the joins clause.

Please correct me if this seems like a glaring mistake to you. It seems to work though. This brings down the Active Record time to just under 1 sec.

Is it common to combine joins and includes?

Thanks!

猫性小仙女 2024-11-13 19:34:24

我已经解决了部分问题(尽管仍然存在一些意外行为)。
我有几个范围,例如locations.current,定义如上所示。

我已经把这个逻辑移到了协会。所以在我的 Person 模型中,我现在有

has_many :current_locations, :source => :location, :through => :location_histories, :conditions => ["`location_histories`.current = ?", true]

And I call

Person.current_locations.first

而不是

Person.locations.current.first.  

所以现在包含按预期进行急切加载。

问题是这搞乱了搜索。由于某种原因,当我包含一个 where 子句时,现在一切似乎都挂了。当我添加到包含中的每个表时,事情首先会变得非常慢,当我包含所有必要的表时,它就会挂起。没有错误。

我确实知道这一点:当我向 where 子句添加符号时,Rails 在查询期间会执行外部联接(如所解释的 此处),这是预期的。但为什么这会导致整个事情崩溃呢?

(这里的一个小问题是我需要字符串比较。为了获得正确的连接,我调用 .where as

.where(:table =>{:column=> 'string'})

这相当于

table.column = 'string'

SQL 中的,但我需要

table.column LIKE '%string%' 

I've figured out PART of the problem (though there is still some unintended behavior).
I had several scopes such as locations.current, defined as indicated above.

I have moved this logic to the association. So in my Person model I now have

has_many :current_locations, :source => :location, :through => :location_histories, :conditions => ["`location_histories`.current = ?", true]

And I call

Person.current_locations.first

instead of

Person.locations.current.first.  

So now the includes do eager load as expected.

The problem is that this messed up the search. For some reason now everything seems to hang when I include a where clause. Things first get dramatically slower with each table that I add to the include and by the time I've included all the necessary tables it just hangs. No errors.

I do know this: when I add symbols to the where clause Rails does an outer join during the query (as explained here), which is what's expected. But why does this cause the whole thing to collapse?

(A minor problem here is that I need string comparisons. In order to get a proper join I call .where as

.where(:table =>{:column=> 'string'})

which is equivalent to

table.column = 'string'

in SQL but I need

table.column LIKE '%string%' 
想念有你 2024-11-13 19:34:24

奇怪的是,对我来说,我得到以下行为:

# fails to eager load tags--it only loads one of the tags for me, instead of all of them.
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags])

但这成功了

Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags], :joins => [:tags])

就像对内部联接表的查询以某种方式搞乱了急切加载。所以你的答案可能是对的。但这里可能发生了一些奇怪的事情。 (此处为 Rails 2.3.8)。

Oddly, for me, I get the following behavior:

# fails to eager load tags--it only loads one of the tags for me, instead of all of them.
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags])

but this succeeds

Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags], :joins => [:tags])

It's like the query on the inner join table is messing up the eager loading somehow. So your answer may be right. But there may be something odd going on here. (Rails 2.3.8 here).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文