需要记住的是,Rails 在实际需要查询结果之前不会执行任何 SQL 查询。 (我将使用 User 而不是 NetworkHost,这样我可以随时向您显示控制台输出)
@users = User.where(first_name: 'Random');nil # No query run
=> nil
@users # query is now run because the results are needed (they are being output to the IRB window)
# User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."first_name" = $1 LIMIT $2 [["first_name", "Random"], ["LIMIT", 11]]
# => #<ActiveRecord::Relation [...]>
@users = User.where(first_name: 'Random') # query will be run because the results are needed for the output into the IRB window
# User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."first_name" = $1 LIMIT $2 [["first_name", "Random"], ["LIMIT", 11]]
# => #<ActiveRecord::Relation [...]>
为什么这很重要?它允许您将要运行的查询存储在实例变量中,并且在您到达可以使用ActiveRecord::Batches 的一些不错方法的视图之前不执行它。特别是,如果您有一些视图(或导出功能等)正在迭代@network_hosts,则可以使用find_each。
# Controller
@users = User.where(first_name: 'Random') # No query run
# view
@users.find_each(batch_size: 1) do |user|
puts "User's ID is #{user.id}"
end
# User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."first_name" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["first_name", "Random"], ["LIMIT", 1]]
# User's ID is 1
# User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."first_name" = $1 AND ("users"."id" > 1) ORDER BY "users"."id" ASC LIMIT $2 [["first_name", "Random"], ["LIMIT", 1]]
# User's ID is 2
# User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."first_name" = $1 AND ("users"."id" > 2) ORDER BY "users"."id" ASC LIMIT $2 [["first_name", "Random"], ["LIMIT", 1]]
# => nil
您的查询直到视图才会执行,此时它一次只会将 1,000 条记录(可配置)加载到内存中。一旦到达这 1,000 条记录的末尾,它将自动运行另一个查询以获取接下来的 1,000 条记录。所以你的记忆更加清醒,代价是额外的数据库查询(通常很快)