【发布时间】:2011-02-05 18:51:29
【问题描述】:
这与a year and change ago的问题有关。
我举了一个应该开箱即用的问题示例,前提是您有可用的 sqlite3:https://github.com/cairo140/rails-eager-loading-counts-demo
安装说明(主分支)
git clone git://github.com/cairo140/rails-eager-loading-counts-demo.git
cd rails-eager-loading-counts-demo
rails s
我在存储库中有更完整的文章,但我的一般问题是这样的。
我怎样才能使 Rails 急切加载计数以最大限度地减少全面的数据库查询?
n+1 问题出现在您对关联使用 #count 时,尽管已通过 #includes(:associated) 将该关联包含在 ActiveRelation 中。一种解决方法是使用#length,但这只有在它被调用的对象已经加载时才有效,更不用说我怀疑它复制了 Rails 内部已经完成的一些事情。此外,使用#length 的一个问题是,如果一开始就没有加载关联并且只需要计数,它会导致不幸的过载。
来自自述文件:
我们可以通过在帖子数组(见附录)上运行#length 来避开这个问题,该数组已经加载,但如果让 count 也随时可用就更好了。它不仅更加一致;它提供了不一定需要加载帖子的访问路径。例如,如果您有一个无论如何都显示计数的部分,但有一半的时间是在加载帖子的情况下调用该部分,而另一半的时间没有加载,您将面临以下情况:
- 使用
#count
- n
COUNT帖子已加载时的样式查询- n
COUNT未加载帖子时的样式查询- 使用
#length
- 已加载帖子时的附加查询为零
- n
*未加载帖子时的样式查询在这两个选项之间,没有占优选项。但是最好修改#count 以推迟到#length 或访问以其他方式存储在幕后的长度,以便我们可以有以下场景:
- 使用修改后的
#count
- 已加载帖子时的附加查询为零
- n
COUNT未加载帖子时的样式查询
那么这里的正确方法是什么?有什么我忽略的(非常、非常可能)吗?
【问题讨论】:
-
如果你是性能导向的,考虑counter-cache:asciicasts.com/episodes/23-counter-cache-column
-
如何“急切地加载”计数?无论如何,计数将需要另一个查询。无论您现在或以后加载计数,您最终都会执行相同数量的查询。
-
使用常规查询将产生一个类似数组的对象,
length不会导致另一个查询。
标签: ruby-on-rails activerecord eager-loading active-relation