【问题标题】:Order and sort_by difference in Ruby on Rails ActiveRecordRuby on Rails ActiveRecord 中的 order 和 sort_by 区别
【发布时间】:2017-03-10 06:30:55
【问题描述】:

我正在尝试根据控制器中的时间戳字段对数据进行排序,请注意时间戳字段可能为空并且可能具有某些值。我写了以下查询。

@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 从数据库中获取最新项目,这是从性能方面获取最新数据的最佳方法还是其他最佳方法?

【问题讨论】:

  • 你确定第一个不是Item.all.sort_by(&:item_timestamp)? AR 模型没有类方法sort_by
  • @MichaelKohl:是的,我正在使用 sort_by 而不是 all,可能是我从选择查询之前的查询中收到了数组而不是活动记录关系。
  • @MichaelKohl 我相信Item.all 是 Item::ActiveRecord_Relation 的一个实例,至少在我使用的 Rails 版本中是这样。从我的 Rails 控制台:` 2.4.4 :002 > Event.all.class => Event::ActiveRecord_Relation 2.4.4 :003 > Event.all.methods.grep /sort/ => [:sort, :sort_by] `

标签: mysql ruby-on-rails ruby activerecord


【解决方案1】:

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

.order 是一种 ActiveRecord 方法,可将ORDER BY 子句添加到 SQL 选择语句中。数据库将处理记录的排序。这在 99% 的情况下更可取。

【讨论】:

  • 还有一个问题,数组和activeRecord关系对象有什么区别,在发出AR请求时,有时我得到数组作为结果,有时我得到activerecord关系对象作为结果。我可以提出一个新问题吗?但我忘记了具体情况。
  • 是的,这是一个完全不同的问题。数组是包含一组对象的简单数据类型(实际上是一个对象)。 ActiveRecord::Relation 是从数据库中延迟加载记录的集合。由于它包含 Enumerable mixin,因此您可以像数组一样遍历它。
  • 有道理 - 谢谢。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      如果您有一个 posts 表和一个 view_counters 表,其中有按文章查看的次数,您无法使用 .order 轻松按总查看次数对帖子进行排序。

      但是使用 sort_by,您可以这样做:

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

      .sort_通过浏览每个元素,获取关系值,然后根据该关系的值进行排序,只需一行代码。

      你可以用&:[attributeName]进一步减少代码,例如:

      @posts = posts.sort_by(&:total_views)
      

      另外,对于你关于反向的最后一个问题,你可以这样做:

      Item.order(item_timestamp: :desc)
      

      【讨论】:

      • 使用order对关联进行排序很容易:@user.posts.joins(:view_counter).order('view_counters.total_views')
      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-29
          • 1970-01-01
          • 2011-01-23
          • 2014-07-02
          相关资源
          最近更新 更多