0

Rails クエリ:

  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

レールで find_each を使用することにより、 details.id >= 0 をチェックし、詳細を昇順で並べ替えます。

ここでは、これら 2 つのアクションを回避したいと考えています。私の場合、処理するデータが大きい場合 (つまり、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 >= 0Railsがデフォルトで行うように、明示的にチェックする必要はありません。

于 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 に答える