Ruby on Rails ActiveRecord中的Order和sort_by差异

时间:2017-03-10 06:30:56

标签: mysql ruby-on-rails ruby activerecord

我正在尝试根据控制器中的timestamp字段对数据进行排序,请注意,timestamp字段可能为null,可能有一些值。我写了以下查询。

@item = Item.sort_by(&:item_timestamp).reverse
            .paginate(:page => params[:page], :per_page =>5)

但是当我将time_timestamp字段值设为NULL但后面的查询有效时,会出现错误。

@item = Item.order(:item_timestamp).reverse
            .paginate(:page => params[:page], :per_page => 5)

有人可以分辨出这两个查询之间的区别,以及使用哪一个查询的条件?

我正在使用order和reverse来从数据库中获取最新项目,这是最好的方法还是有其他最佳方法从性能方面获取数据库中的最新数据?

6 个答案:

答案 0 :(得分:8)

sort_by在Ruby中执行,所以如果你有一个nil值,事情会以类似的方式破坏:

[3, nil, 1].sort
#=> ArgumentError: comparison of Fixnum with nil failed

order由您的RDBMS执行,通常可以使用NULL值执行。您甚至可以通过在NULL VALUES条款中添加NULL FIRST(通常是默认值)或NULL LAST来指定要放置ORDER BY的位置吗?

答案 1 :(得分:6)

.sort_by是来自Enumerable的Ruby方法,用于对数组(或类似对象的数组)进行排序。使用.sort_by将导致所有记录从数据库加载到服务器内存中,这可能导致严重的性能问题(以及您的nil值问题)。

.order是一个ActiveRecord方法,它为SQL select语句添加ORDER BY子句。数据库将处理对记录的排序。 99%的情况下这是优选的。

答案 2 :(得分:0)

嘿,你不需要在那个查询中排序,它会工作很长时间,如果你使用DB,你应该总是使用:order,解决你的问题

@item = Item.order('item_timestamp DESC NULLS LAST').paginate(:page => params[:page], :per_page => 5)

答案 3 :(得分:0)

就像我之前所说的,.order更快,在大多数情况下就足够了,但是例如,如果您想按关系中的值进行排序,则有时需要sort_by。

如果您有一个posts表和一个view_counters表,其中有按文章显示的视图数,则无法轻松地用.order对发布的总数进行排序。

但是使用sort_by,您可以执行以下操作:

posts = @user.posts.joins(:view_counter)
@posts = posts.sort_by { |p| p.total_views }

.sort_通过浏览每个元素,获取关系值,然后仅用一条代码行按此关系的值进行排序。

您可以使用&:进一步简化代码。

@posts = posts.sort_by(&:total_views}

对于最后一个关于反向的问题,您可以执行以下操作:

Item.order(item_timestamp: :desc)

答案 4 :(得分:0)

使用sort_by会中断活动记录缓存,并且如前所述,将所有记录加载到RAM内存中。

在写下查询时,请始终考虑一下SQL和内存世界,它们是2个独立的东西。就像拥有档案(SQL)和购物车(内存)一样,您将从档案中取出的文件放入其中以供以后使用。

答案 5 :(得分:0)

正如大多数人提到的,主要区别在于 sort_by 是一种 Ruby 方法,而 order 是 Rails ActiveRecord 方法。但是,使用它们的场景可能因情况而异。例如,如果您已经从数据库中检索了数据并希望对加载的数据进行排序,那么您可能会遇到 sort_by 可能适用的场景。如果您使用 order on 那么您可能会引入 n+1 问题并在您已经加载数据时再次转到数据库。