【问题标题】:Better solution to find in list of ID?在 ID 列表中找到更好的解决方案?
【发布时间】:2014-08-15 16:24:06
【问题描述】:

假设我有一个 id 数组,大概有 100000 个 id。在我无法创建临时表来执行 JOIN 的情况下。对我来说简单的解决方案是:

Product.where(id: ids)

这将生成WHERE IN 子句,当数组很大时,这似乎会伤害 Mysql。我想知道是否有更好的解决方案?

【问题讨论】:

    标签: ruby-on-rails activerecord rails-activerecord where-in


    【解决方案1】:

    如果它是一个连续范围,您可以尝试使用BETWEEN - Product.where id: 1..100000 可以解决问题。

    否则,whole_array_of_ids.each_slice(number_of_ids_mysql_can_handle){ |ids| Product.where(id: ids) } - 多个查询,但仍可管理。 Read about each_slice and more goodies here.

    此外,许多 AR finder 方法都有 batch_size 参数,但它似乎在这里对您没有帮助,因为它会使用所有 id 构建整个查询,然后在最后加上 LIMIT

    【讨论】:

    【解决方案2】:

    使用 find_each 限制一次加载的记录数。 find_each 默认一次加载 1000 条记录,但您可以通过设置 :batch_size 选项来调整:

    这将一次查询数据库 1,000 条记录:

    Product.where(id: ids).find_each do |product|
      # do something with the product
    end
    

    或者您可以更改一次加载的记录数(50 条怎么样?):

    Product.where(id: ids).find_each(batch_size: 50) do |product|
      # do something with the product
    end
    

    【讨论】:

    • 当您在 IN 子句中粘贴大量 id 时,这些都没有帮助。当您有像select * from posts where id in (1,2,3, ... ,1234567890) 这样的查询时,数据库将在运行选择本身时阻塞。例如,Oracle 在 IN 子句中有 1000 个项目的硬性限制。其他人只会因为那里有几千件物品而变得难以忍受。
    猜你喜欢
    • 2014-07-20
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    相关资源
    最近更新 更多