Ruby在哪里有find_each

时间:2013-03-17 03:48:40

标签: ruby-on-rails ruby activerecord

我正在查看官方Rails文档,其中显示了如何使用“find_each”方法。这是他们给出的一个例子

Person.where("age > 21").find_each do |person|
  person.party_all_night!
end

一次处理1000条记录。但是,我仍然感到困惑。这如何转化为SQL?幕后发生了什么,允许Ruby一次只处理1000条记录?

我有点困惑的原因是因为看起来Person.where(“age> 21”)会首先执行,这会返回所有结果。

例如:

Person.where("age > 21").limit(10)

首先会返回所有记忆中的人,然后给你前10个,对吧?

3 个答案:

答案 0 :(得分:7)

Person.where("age > 21")仅返回ActiveRecord关系。它不会返回所有结果。

Person.where("age > 21").limit(10)不会将所有模型加载到内存中,这将是非常糟糕和无法使用的。它只加载10。

find_each一次不会真正处理1000条记录。它加载1000条记录,然后处理它们中的每一条。

答案 1 :(得分:6)

我建议从控制台运行它,查看SQL或阅读源代码。

例如:

User.find_each(:batch_size => 40) do |user| end
  User Load (1.0ms)  SELECT "users".* FROM "users" WHERE ("users"."id" >= 0) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 96) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 156) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 219) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 272) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 314) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 355) ORDER BY "users"."id" ASC LIMIT 40

或者

bundle show activerecord
point your favorite code editor at that location and find the source

答案 2 :(得分:2)

Ruby有一个可爱的可爱功能,称为 codeblocks 。是什么让它真的很棒,每个方法都假设<静默>接收代码块作为最后一个参数。有可能动态检查代码块是否与if block_given?一起提供。

我想你想知道为什么Ruby 单独使用where返回数据而只是使用where.whatever链准备它?好吧,ActiveRecord隐式检查是否给出了代码块并执行了底层SQL语句并遍历结果返回一个带有已准备但尚未执行的SQL语句的迭代器。后者将被延迟执行并按需缓存。例如,Array.each使用相同的做法。在场景背后正在执行类似的事情:

sql_prepare
if block_given?
  @cache = sql_execute_and_cache
  @cache.each { yield @cache }
end

希望它有所帮助。