使用Rails和Postgres处理大型结果集的最佳方法是什么?直到今天我都没有遇到问题,但现在我正在尝试返回@network_hosts = []
@host_count = 0
@company.locations.each do |l|
if l.grace_enabled == nil || l.grace_enabled == false
l.network_hosts.each do |h|
@host_count += 1
@network_hosts.push(h)
@network_hosts.sort! { |x,y| x.ip_address <=> y.ip_address }
@network_hosts = @network_hosts.first(5)
end
end
end
的124,000记录对象,它有效地帮助了我的开发服务器。
我的主动记录并不是最漂亮的,但我很确定清理它并不会对性能有所帮助。
@network_hosts
最后,我需要能够将@network_hosts
返回到控制器以便处理到视图中。
这是Sidekiq能够提供帮助的东西,还是会有那么长的时间?如果Sidekiq是要采取的路径,那么当作业以异步方式运行时,如何处理页面加载时没有{{1}}对象?
答案 0 :(得分:1)
我相信你想(1)摆脱所有循环(你已经进行了大量的查询)和(2)用你的AR查询而不是在数组中进行排序。
也许是这样的:
NetworkHost.
where(location: Location.where.not(grace_enabed: true).where(company: @company)).
order(ip_address: :asc).
tap do |network_hosts|
@network_hosts = network_hosts.limit(5)
@host_count = network_hosts.count
end
这样的事情应该在单个数据库查询中完成。
我必须对你的关联如何设置以及你正在寻找grace_enabled不为真(ni或false)的位置做出一些假设。
我没有测试过这个,所以它可能是错误的。但是,我认为方向是正确的。
答案 1 :(得分:1)
要记住的事情,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条记录。所以你的内存更加理智,代价是额外的数据库查询(通常非常快)