0

轨道查询:

  Detail.created_at_gt(15.days.ago.to_datetime).find_each do |d|
      //Some code
  end

等效的mysql查询:

  SELECT * FROM `details` WHERE (details.id >= 0) AND
                 (details.created_at > '2012-07-01 12:22:32')
                  ORDER BY details.id ASC LIMIT 1000

通过在 rails 中使用 find_each 它检查 details.id >= 0 并按升序排列细节。

在这里,我想避免这两个操作,因为在我的情况下,当我有大量数据要处理(即)created_at 上的索引失败时,它正在扫描整个表。所以这样做是低效的。请任何人帮助。

4

3 回答 3

2

在这里,您find_in_batches使用的来源find_each

http://apidock.com/rails/ActiveRecord/Batches/find_in_batches

单击显示源链接。基本线路是:

relation = relation.reorder(batch_order).limit(batch_size)
records = relation.where(table[primary_key].gteq(start)).all

records = relation.where(table[primary_key].gt(primary_key_offset)).to_a

您必须按主索引或其他唯一索引对记录进行排序,以便批量处理并选择下一批。您不能按批次进行,created_at因为它不是唯一的。但是您可以混合排序created_at和选择 unique id

relation = relation.reorder('created_at ASC, id ASC').limit(batch_size)
records = relation.where(table[primary_key].gteq(start)).all

#....

while records.any?
    records_size = records.size
    primary_key_offset = records.last.id
    created_at_key = records.last.created_at

    yield records

    break if records_size < batch_size

    if primary_key_offset
      records = relation.where('created_at>:ca OR (created_at=:ca AND id>:id)',:ca=>created_at_key,:id=>primary_key_offset).to_a
    else
      raise "Primary key not included in the custom select clause"
    end
end

如果您绝对确定没有具有相同created_at值的记录将重复bach_size多次,您可以将其created_at用作批处理中的唯一键。

无论如何,您需要索引created_at才能有效。

于 2012-07-16T09:12:47.450 回答
0
Detail.where('created_at > ? AND id < ?', 15.days.ago.to_datetime, 1000).order('details.id ASC')

你不必details.id >= 0像 Rails 默认为你做的那样显式地检查。

于 2012-07-16T08:03:07.093 回答
0

如果您将使用范围和 ARel 风格的查询,那就更好了:

class Detail < ActiveRecord::Base
  table = self.arel_table

  scope :created_after, lambda { |date| where(table[:created_at].gt(date)).limit(1000) }
end

您可以找到在某个日期之后创建的 1000 条记录:

@details = Detail.created_after(15.days.ago.to_date_time)
于 2012-07-16T08:26:49.793 回答