如何“重新加载” Rails 2.3 中具有急切加载条件的集合?
我正在维护一个用 2.3(我认为是 .5)编写的旧 Rails 应用程序。有一个低效的选择导致了我正在尝试修复的旧 N+1 问题。
首先,在 switch 中加载带有不同 find_by_sql 语句的 Widget 集合。之后是执行 N+1 操作的 Widget.association.select。我想用基于 find_by_sql 中 Widget 的 id 的急切加载 Widget 来替换此选择循环。我意识到我可能可以将这些合并到 1 个查询中,但是 find_by_sql 相当复杂,因此此时我正在采取一些小步骤来优化为希望 2 个查询。
所以基本上我有
@widgets = Widget.find_by_sql...
现在我想使用 @widgets 来做类似的事情
@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN ", @widgets.ids])
I'm maintaining an old rails app written in 2.3(.5 I think). There's an inefficient select that's resulting in the old N+1 problem that I'm trying to fix.
First, a collection of Widgets is loaded with different find_by_sql statements in a switch. After that comes the Widget.association.select that's doing the N+1. I want to replace this select loop with an eager load of Widgets based on the ids of the Widgets from the find_by_sql. I realize I could probably combine these into 1 query, but the find_by_sql are fairly complex, so at this point I'm taking small steps to optimize into hopefully 2 queries.
So basically I have
@widgets = Widget.find_by_sql...
and now I want to use @widgets to do something like
@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN ", @widgets.ids])
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用
collect
或map
获取要在查询的IN...
部分中使用的 ID 数组...或者,因为 Rails 会很好地处理它并在每个对象上调用
.to_param
,所以您可以简单地使用@widgets
数组(这是假设它们是一个实例的Widget
并显然响应.to_param
)...正如您在问题中所说,将两个查询绑定在一起将是处理此问题的一种更优雅的方式。如果您打算这样做,您可能需要考虑让第一个查询仅选择 id,这样至少您不会不必要地在内存中存储两批相同的数据。
You could use
collect
ormap
to get an array of the IDs to use in theIN...
part of the query...Or, because Rails will deal with it nicely and call
.to_param
on each of the objects, you could simply use the array of@widgets
(this is, assuming they are an instance ofWidget
and respond to.to_param
obviously)...As you said in your question, tying the two queries together would be a far more graceful way of dealing with this. If you are going to do it this way, you might want to consider getting the first query to select the ids only so at least you're not needlessly storing two lots of the same data in memory.