Rails + ActiveRecord +优化:有更好的方法来更新300,000条记录吗?

时间:2013-06-14 21:36:47

标签: ruby-on-rails

所以我有一个执行此操作的rake任务:

  wine_club_memberships = WineClubMembership.pluck(:billing_info_id)
  total_updated = BillingInfo.joins(:order).where(["orders.ordered_date < (CURRENT_DATE - 90) AND billing_infos.card_number IS NOT NULL AND billing_infos.card_number != '' AND billing_infos.id NOT IN (?)", wine_club_memberships]).update_all("card_number = ''")
  log.error("Total records updated #{total_updated}")

事实是BillingInfo有300,000条记录,我想知道所有这些joinswhereupdate_all是否与使用纯SQL相同。目前它效率不高,因为我在声明中填写了大量WineClubMembership条记录。

有更有效的方法吗?虽然这是一个长期丑陋的陈述,但我认为它在大多数情况下都是有效的,因为它在数据库的一两次点击中完成所有操作。但是,我周围的人都在想,必须有其他“Rails方法”能够以更好的方式做到这一点,不会影响生产网站的性能。

我确实看到过“批量”搜索,但我不确定这是否会有所帮助。

更新

我正在使用Postgres 9.1+。在我的activerecord搜索的旧版本(稍微简单一点)中,这就是出现的内容:

Ruby代码:

  wine_club_memberships = WineClubMembership.pluck(:billing_info_id)
  total_updated = BillingInfo.joins(:order).where(["orders.ordered_date < (CURRENT_DATE - 90) AND billing_infos.id NOT IN (?)", wine_club_memberships]).update_all("card_number = ''")

SQL生成:

  SQL (127848.6ms)  UPDATE "billing_infos" SET card_number = '' WHERE "billing_infos"."id" IN (SELECT "billing_infos"."id" FROM "billing_infos" INNER JOIN "orders" ON "orders"."id" = "billing_infos"."order_id" WHERE (orders.ordered_date < (CURRENT_DATE - 90) AND billing_infos.id NOT IN (423908,390663,387323,402393,383446,416114,391009,456371,384305,386681,384382,384418, ...)))

1 个答案:

答案 0 :(得分:0)

如果您的数据库管理最终NOT IN比较的源代码,可能会在数据库中进行优化以便处理它。让sql管理id列表,而不是传递300,000项长数组。如果您的数据库允许尝试类似

的内容
... NOT IN (SELECT billing_info_id FROM wine_club_memberships)").update_all("card_number = ''")

就Rails特定的加速速度的方法而言,除了将纯sql字符串传递给dbs之外,你通常不会做得更好(性能方面,如果不是可维护性)。 / p>