使用ActiveRecord验证旧表

时间:2009-09-29 13:30:34

标签: ruby-on-rails ruby activerecord

美好的一天,

我们正在从一个系统到Rails应用程序进行数据迁移。我们正在使用的一些表非常大,使用ActiveRecord一次将它们移动超过1条记录需要太长时间。因此,我们使用SQL复制表并在事后验证。

逐个验证检查仍然很慢,但SQL副本的速度增加超过了它。然而,这并没有解除我们的渴望,看看我们是否可以更快地进行验证检查。我们尝试将表拆分为块并将每个块传递给线程但实际上执行速度较慢。

问题是,大表,当前正逐行迭代进行验证,如此

Model.find_each do |m|
  logger.info "M #{m.id} is not valid" unless m.valid?
end

任何人都有关于如何提高速度的建议吗?

由于

对等

编辑我不应该特别说这段代码。我们正在寻找关于如何同时运行这些建议的建议,为每个进程提供一大块数据,而不需要每个进程一台机器

2 个答案:

答案 0 :(得分:2)

find_each正在使用find_in_batches,默认情况下一次获取1000行。您可以尝试使用batch_size选项。你上面的方式看起来非常理想;它是从数据库中批量获取并迭代每个数据库,您需要这样做。我会监视您的RAM以查看批量大小是否最佳,如果您当前使用的是1.8。*,还可以尝试使用Ruby 1.9.1来加快速度。

http://api.rubyonrails.org/classes/ActiveRecord/Batches/ClassMethods.html#M001846

答案 1 :(得分:0)

我喜欢zgchurch的回应作为起点。

我要补充的是线程绝对不会对此有所帮助,特别是因为Ruby使用绿色线程(至少在1.8.x中),所以无论如何都没有机会使用多个处理器。即使不是这种情况,这种操作很可能足够IO,以至于你会让IO争用进入任何多核的利益。

现在,如果你真的想加快速度,你应该看一下实际的验证,找出一种更有效的方法来实现它们。在大多数验证情况下,只需加载所有行并实例化ActiveRecord对象就会主导性能。您可能只需花费90-99.99%的时间从内存中加载和卸载数据。

在这些类型的情况下,我倾向于使用原始SQL。您可以比原始ActiveRecord验证回调更快地验证外键完整性数万倍。当然,这种方法的可行性取决于验证的实际细节。即使您需要比SQL更丰富的东西来定义有效性,您仍然可以获得10-100倍的速度增加,只需使用更薄的SQL接口加载最小数据并直接检查数据。如果是这种情况,Perl或Python可能是原始性能的更好选择。