我正在查看官方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个,对吧?
答案 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
希望它有所帮助。