我有以下代码,但是处理1000条记录大约需要3分钟。在生产中,我期望有1,000,000条记录,这种性能对于处理如此数量的记录是不可接受的。有什么办法能快一点吗?我是Rails的新手,所以还在不断学习。
在下面的例子中,我试图迭代给定供应商的所有产品,如果产品item_id不在xml提要中,则将产品id包含到我将在下一步迭代的数组中,并将产品标记为"存档/非活动"。问题主要出在代码的第一部分,它需要太多的时间来处理。
self.products.where( :archived => false ).find_each do |p|
archive = !@xml_feed.css("ITEM_ID").to_s.downcase.include?("<item_id>#{p.item_id}</item_id>")
archived_product_ids << p.id if archive
end
if archived_product_ids.size > 0
# update all archived products
Product.where('id IN (?)', archived_product_ids).update_all( :archived => true, :archived_at => Time.now, :active => false )
logger.info "Products #{archived_product_ids.to_s} has been archived and deactivated."
end
这是我的控制台的输出,您可以看到处理每1000条记录之间的3分钟:
[2015-08-31T22:28:18.090063 #28332] DEBUG -- : Product Load (5.0ms) SELECT "products".* FROM "products" WHERE "products"."supplier_id" = $1 AND "products"."archived" = $2 ORDER BY "products"."id" ASC LIMIT 1000 [["supplier_id", 2], ["archived", "f"]]
[2015-08-31T22:31:14.767496 #28332] DEBUG -- : Product Load (5.3ms) SELECT "products".* FROM "products" WHERE "products"."supplier_id" = $1 AND "products"."archived" = $2 AND ("products"."id" > 2513) ORDER BY "products"."id" ASC LIMIT 1000 [["supplier_id", 2], ["archived", "f"]]
我想我会首先将复杂的表达式赋值给一个变量,因此它只计算一次,并使用pluck来避免实例化所有这些产品对象:
item_ids = @xml_feed.css("ITEM_ID").to_s.downcase
self.products.where( :archived => false ).pluck(:id, :item_id) do |p|
archive = !item_ids.include?("<item_id>#{p[1]}</item_id>")
archived_product_ids << p[0] if archive
end
尝试反向搜索。您正在提取所有记录,并在@xml_feed中查找id。为什么不尝试在@xml_feed中提取所有id,然后在数据库中查询这些id呢?
如果@xml_feed中大约有100个条目,例如,您可以让数据库在查询中在100万条记录中进行所有匹配id的搜索,这是数据库擅长的。
谢谢大家的宝贵建议。我能够将处理1000条记录的时间从3分钟减少到5秒,这是完美的!每个供应商平均有大约8k条记录和不同的xml提要源,所以我现在可以运行cron作业来每天分别为每个供应商更新产品。这应该在1.5小时内完成所有(100万)和一个工人,这是可以接受的。
# archive products if they are not present in the xml feed
item_ids = @xml_feed.css("ITEM_ID").to_s
self.products.where( :archived => false ).pluck(:id, :item_id).each do |p|
archive = !item_ids.include?("<ITEM_ID>#{p[1]}</ITEM_ID>")
if archive
archived_product_ids << p[0]
archived_products += 1
new_import_record.update_attributes(archived_products: archived_products)
end
end