如何“重新加载” Rails 2.3 中具有急切加载条件的集合?

发布于 2024-10-18 17:50:13 字数 539 浏览 1 评论 0原文

我正在维护一个用 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 技术交流群。

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

发布评论

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

评论(1

紧拥背影 2024-10-25 17:50:13

您可以使用 collectmap 获取要在查询的 IN... 部分中使用的 ID 数组...

@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN (?)", @widgets.collect(&:id)])

或者,因为 Rails 会很好地处理它并在每个对象上调用 .to_param ,所以您可以简单地使用 @widgets 数组(这是假设它们是一个实例的 Widget 并显然响应 .to_param)...

@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN (?)", @widgets])

正如您在问题中所说,将两个查询绑定在一起将是处理此问题的一种更优雅的方式。如果您打算这样做,您可能需要考虑让第一个查询仅选择 id,这样至少您不会不必要地在内存中存储两批相同的数据。

You could use collect or map to get an array of the IDs to use in the IN... part of the query...

@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN (?)", @widgets.collect(&:id)])

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 of Widget and respond to .to_param obviously)...

@widgets_and_more = Widget.find(:all, :include => :widget_assoc, :conditions => ["widgets.id IN (?)", @widgets])

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.

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