首页 > 解决方案 > 比较 2 个大型 ActiveRecord 关系进行排序

问题描述

我有 2 个大ActiveRecord::Relations的,每个都有 10 或 100 的数千条用户记录,我们称它们ar1ar2. 我想进行排序ar1,以便所有出现在 中的记录ar2都放在ar1.

这很容易做到sort_by,但由于记录的数量如此之大,sort_by在某些情况下执行需要一分钟以上。

我认为我最好的选择是尝试通过 ActiveRecord 以这种方式对记录进行排序,但我找不到任何方法来做到这一点。有没有办法使用 ActiveRecord 或其他方法快速完成此结果?

谢谢!

编辑:

这是我使用的排序代码:ar1.sort_by { |e| ar2.index(e) || Float::INFINITY }

标签: ruby-on-railsrubyactiverecordruby-on-rails-6

解决方案


我会首先说你并不需要sort_by

您可以通过以下方式实现相同的目标:

ar1.sort_by { |e| ar2.index(e) || Float::INFINITY }

采用类似于以下的方法:

result = ((ar2 & ar1) + ar1).uniq

这要快得多。

这是支持此建议的简单基准。

require 'benchmark'
ar1 = 100_000.times.map {|x|( 100_000_000 * rand).to_i }.uniq
ar2 = 100_000.times.map {|x|( 100_000_000 * rand).to_i }.uniq

puts ar1.size
puts ar2.size

Benchmark.bm do |x|
  result_2 = []
  result_1 = []
  x.report('sort') do
    result_2 = ar1.sort_by { |e| ar2.index(e) || Float::INFINITY }
    result_2.size
  end

  x.report('array') do
    result_1 = ((ar2 & ar1) + ar1).uniq
    result_1.size
  end

  puts result_1.size
  puts result_2.size
  puts result_1 == result_2
end

给出了一些不错的结果

       user     system      total        real
sort 45.287331   0.012233  45.299564 ( 45.539641)
array  0.010782   0.004000   0.014782 (  0.014792)

我省略了一些验证输出。

现在是 ActiveRecord 部分。根据ar2集合大小,您可以检索 id 并以此对第二个查询进行排序。鉴于ar1 = first_query.order(first_order)

ar2_ids = second_query.pluck(:id)

ar1 = first_query.order("FIELD(id, #{ar2_ids.join(',')}), first_order")

这将保留第ar2一个和其他稍后。您将需要调查 id 的大小,ar2因为根据您的数据库,提供具有数千个 id 的订单查询可能不是最理想的。

在考虑了这个问题之后,我会选择数组操作方法来保持简单。我不会选择数据库解决方案,因为它很可能会破坏查询的可读性,太多了。

这一切都取决于你的问题的细节!我希望这有帮助。


推荐阅读