[英]What's the right way to do counts in Rails?
I have a rails app with many following pieces of code:我有一个 Rails 应用程序,其中包含许多以下代码:
Our active community of <%= Account.find_all_by_admin(false).count %>
My question is is this the right way to do counts on views?我的问题是,这是对视图进行计数的正确方法吗? It seems so "dirty" is there a more railish, way to do counts?
看起来如此“肮脏”有没有更荒谬的计数方法? I'm thinking named scopes perhaps, but I just want to be sure that these type of things won't have a greater impact in performance.
我可能在考虑命名范围,但我只想确保这些类型的东西不会对性能产生更大的影响。
Thank You,谢谢你,
You don't need a name scope to perform a count.您不需要名称范围来执行计数。
Account.where(:admin => false).count
But named scopes are an excellent way to make your code more reusable.但是命名范围是使代码更可重用的极好方法。
Named scopes don't have any noticeable performance impact on your application.命名范围对您的应用程序没有任何明显的性能影响。
I would recommend you to avoid direct access to database in my templates because then you're losing a bit of flexibility when it comes to caching.我建议你避免在我的模板中直接访问数据库,因为那样你会在缓存方面失去一些灵活性。
Try to prepare all the data you need to render in your action instead and then use meaningful instance variables like @number_of_accounts
or @accounts.count
.尝试准备您需要在操作中呈现的所有数据,然后使用有意义的实例变量,例如
@number_of_accounts
或@accounts.count
。
This will make your views cleaner and easier to debug and also a bit more DRY if you render action in different formats (html, json, etc)如果您以不同的格式(html、json 等)呈现动作,这将使您的视图更清晰、更易于调试,并且也会更 DRY
As to how do you get your numbers - it doesn't really matter that much, just move away from find_* methods towards scoping and write readable code至于你如何得到你的数字 - 它并不那么重要,只是从 find_* 方法转向范围和编写可读的代码
In rails 3 a simple call to count issues a simple count request:在 rails 3 中,一个简单的 count 调用会发出一个简单的 count 请求:
Contact.count
is resolved as:被解析为:
SELECT COUNT(*) AS count_id FROM "contacts"
a find all by field name will resolve as: find all by field name 将解析为:
Contact.find_all_by_country("Canada")
SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
I would recommend indexing your admin column for faster lookups and this can be translated into a named scope, but that by itself will only predefine the query, not optimize it.我建议为您的管理列建立索引以加快查找速度,这可以转换为命名范围,但它本身只会预定义查询,而不是优化它。
It is important to note that if you issue重要的是要注意,如果您发出
Contact.find_all_by_country("Canada").count
count
is a method on the array class and doesn't actually issue a count on the database: count
是数组类上的一个方法,实际上并不对数据库发出计数:
Contact.find_all_by_country("Canada").count
SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
A named scope shouldn't have an impact on performance命名范围不应影响性能
scope :not_admin, where(:admin => false)
Then you can have Account.not_admin.count
然后你可以有
Account.not_admin.count
Edited per DGM's comment: To check the generated SQL in a console, compare Account.not_admin.to_sql
with Account.find_all_by_admin(false).to_sql
根据 DGM 的评论进行编辑:要在控制台中检查生成的 SQL,
Account.find_all_by_admin(false).to_sql
Account.not_admin.to_sql
与Account.find_all_by_admin(false).to_sql
进行比较
You can use following query instead of Account.where(:admin => false).count
您可以使用以下查询代替
Account.where(:admin => false).count
Account.select(:id).where(:admin => false).count
Just select one column, instead of selecting all.只需选择一列,而不是选择全部。 It generates the following query and it is faster than the previous one:
它生成以下查询,并且比前一个查询更快:
SELECT COUNT("accounts"."id") FROM "accounts" where admin = false
You should create an instance variable
in the controller and use it in the view.您应该在控制器中创建一个
instance variable
并在视图中使用它。 This will make you view clear.这会让你看得清楚。
@accounts_count = Account.where(admin: false).count
And use it in the view like `<%= @accounts_count %>并在视图中使用它,如 `<%= @accounts_count %>
If you want to loop though the results along with the count, you can use the following way:如果要循环遍历结果和计数,可以使用以下方式:
@accounts = Account.where(admin: false)
in view, write like below:鉴于,写如下:
<%= @accounts.count %>
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
But the above way will fire 2 queries, 1 for count and other for the loop.但上述方式将触发 2 个查询,1 个用于计数,另一个用于循环。
Correct Approach正确的做法
Use size
instead of count
.使用
size
而不是count
。 It will fire 1 query but you need to change the order of count in your view like:它将触发 1 个查询,但您需要更改视图中的计数顺序,例如:
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
<%= @accounts.size %>
If you want the same order, then load the user object first like below如果你想要相同的顺序,那么首先加载用户对象,如下所示
<%= @accounts.load.size %>
// For looping account
<% @accounts.each do |account| %>
# do some stuff
<% end %>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.