我有以下代码,但处理1000条记录大约需要3分钟。在制作中,我预计会有1 000 000条记录,这种表现对于处理这么多的记录是不可接受的。知道如何加快速度吗?我是Rails的新手,所以还在忙着学习东西。
在下面的示例中,我尝试迭代给定供应商的所有产品,如果产品item_id不在xml Feed中,请将产品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"]]
答案 0 :(得分:0)
我想我会先将复杂表达式赋给变量,所以它只计算一次,并使用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
答案 1 :(得分:0)
尝试反转您的搜索。您正在绘制所有记录,并在@xml_feed中查找ID。为什么不尝试在@xml_feed中绘制所有ID,然后查询数据库中的那些?
例如,如果@xml_feed中有大约100个项目,您可以让数据库在一百万条记录中进行所有搜索,以便在查询中匹配id,这是数据库擅长的。
答案 2 :(得分:0)
感谢所有有价值的提示。我能够将处理1 000条记录的时间从3分钟减少到5秒,这是完美的!每个供应商平均拥有大约8k记录和不同的xml供稿源,因此我现在可以每天单独运行一个cron作业来更新每个供应商的产品。对于所有(100万)和一名工人,这应该在1.5小时内完成,这是可以接受的。
# 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