![](/img/trans.png)
[英]'in' and 'not in' counts do not add up - what's wrong?
[英]What's the right way to do counts in Rails?
我有一个 Rails 应用程序,其中包含许多以下代码:
Our active community of <%= Account.find_all_by_admin(false).count %>
我的问题是,这是对视图进行计数的正确方法吗? 看起来如此“肮脏”有没有更荒谬的计数方法? 我可能在考虑命名范围,但我只想确保这些类型的东西不会对性能产生更大的影响。
谢谢你,
您不需要名称范围来执行计数。
Account.where(:admin => false).count
但是命名范围是使代码更可重用的极好方法。
命名范围对您的应用程序没有任何明显的性能影响。
我建议你避免在我的模板中直接访问数据库,因为那样你会在缓存方面失去一些灵活性。
尝试准备您需要在操作中呈现的所有数据,然后使用有意义的实例变量,例如@number_of_accounts
或@accounts.count
。
如果您以不同的格式(html、json 等)呈现动作,这将使您的视图更清晰、更易于调试,并且也会更 DRY
至于你如何得到你的数字 - 它并不那么重要,只是从 find_* 方法转向范围和编写可读的代码
在 rails 3 中,一个简单的 count 调用会发出一个简单的 count 请求:
Contact.count
被解析为:
SELECT COUNT(*) AS count_id FROM "contacts"
find all by field name 将解析为:
Contact.find_all_by_country("Canada")
SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
我建议为您的管理列建立索引以加快查找速度,这可以转换为命名范围,但它本身只会预定义查询,而不是优化它。
重要的是要注意,如果您发出
Contact.find_all_by_country("Canada").count
count
是数组类上的一个方法,实际上并不对数据库发出计数:
Contact.find_all_by_country("Canada").count
SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
命名范围不应影响性能
scope :not_admin, where(:admin => false)
然后你可以有Account.not_admin.count
根据 DGM 的评论进行编辑:要在控制台中检查生成的 SQL, Account.find_all_by_admin(false).to_sql
Account.not_admin.to_sql
与Account.find_all_by_admin(false).to_sql
进行比较
您可以使用以下查询代替Account.where(:admin => false).count
Account.select(:id).where(:admin => false).count
只需选择一列,而不是选择全部。 它生成以下查询,并且比前一个查询更快:
SELECT COUNT("accounts"."id") FROM "accounts" where admin = false
您应该在控制器中创建一个instance variable
并在视图中使用它。 这会让你看得清楚。
@accounts_count = Account.where(admin: false).count
并在视图中使用它,如 `<%= @accounts_count %>
如果要循环遍历结果和计数,可以使用以下方式:
@accounts = Account.where(admin: false)
鉴于,写如下:
<%= @accounts.count %>
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
但上述方式将触发 2 个查询,1 个用于计数,另一个用于循环。
正确的做法
使用size
而不是count
。 它将触发 1 个查询,但您需要更改视图中的计数顺序,例如:
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
<%= @accounts.size %>
如果你想要相同的顺序,那么首先加载用户对象,如下所示
<%= @accounts.load.size %>
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.