检查ActiveRecord集合中是否有记录的正确方法

时间:2017-12-12 11:09:59

标签: ruby-on-rails activerecord

在我看来,我有一个这样的代码:

<% if @posts.any? %>
  <% @posts.each do |post| %>
    ...
  <% end %>
<% else %>
  <p>No posts found</p>
<% end %>

这在我的控制台日志中生成:

...
Post Exists (1.4ms)  SELECT  1 AS one FROM `posts` LIMIT 1 OFFSET 0
...
Post Load (1.1ms)  SELECT  `posts`.* FROM `posts` LIMIT 50 OFFSET 0
...

所以这个触发器2在我的数据库上查询。如果我以这种方式改变视图

<% unless @posts.blank? %>
  <% @posts.each do |post| %>
    ...
  <% end %>
<% else %>
  <p>No posts found</p>
<% end %>

只会触发一个查询:

...
Post Load (1.1ms)  SELECT  `posts`.* FROM `posts` LIMIT 50 OFFSET 0
...

如果我使用@posts.exists?@posts.empty?@posts.any?,我会执行两个查询,如果我使用@posts.blank?@posts.present?我只执行一次查询。

所以我的问题是:有一种最佳实践来检查集合是否为空?我何时应该使用exists?empty?any?present?blank?

3 个答案:

答案 0 :(得分:1)

存在?应该使用它,因为它是最快的。

@post.blank? would retrieve all the post and count them.

!@post.present? would retrieve all the post and count them.

@post.empty? would retrieve the count of post.

空白?,现在?,空?如果您预先加载了记录,则可以使用。

@post.any? would be exactly the same as the previous option.

任何?检索关系中的记录(除非它们是预加载的),将它们表示为数组,然后调用.where存在?总是查询数据库,从不依赖于预加载的记录,只检索到一条记录,这使得这种方法比任何记录更快?

@post.exists? would retrieve the first post. That makes this approach fastest among those five.

答案 1 :(得分:0)

检查完后(对于预加载的记录),我得到以下结果:

  • 生成其他查询:

    • exists?(0.3ms)
    • empty?(0.3ms)
    • any?(0.4ms)
    • present?(0.5毫秒)
  • 不会生成其他查询:

    • blank?

在生成其他查询的方法组中,除present?exists?empty?any?present?之外的所有方法都会生成以下查询:

SELECT  1 AS one FROM `posts` LIMIT 1

只有present?生成不同的查询(这有点耗时):

SELECT `posts`.* FROM `posts`

因此,如果您真的想减少查询次数,请使用blank?。在其他情况下,您可以使用任何方法,但我建议避免使用present?

答案 2 :(得分:0)

另一种有趣的(也许是不直观的)方法可以解决您的示例中的双重查询问题:

<% if @posts.each do |post| %>
  // do something with each post here
<% end.empty? %>
  <p>No posts found</p>
<% end %>

这将获取each的结果,该结果是集合(已加载到内存中,不再从数据库中检索),并检查其中是否包含任何记录。