LoginSignup
1
1

More than 5 years have passed since last update.

find_in_batchesは降順で処理できない

Last updated at Posted at 2016-07-13

表題の通り。

active_recordにfind_in_batchesという便利なメソッドがある。

通常テーブルのデータを処理する際はeachを使うことが多いと思われるが、そのデータ量が多い場合などはメモリを食ってしまいうまく処理できないことがある。

こういった場合、find_in_batchesを使えば一度にメモリにロードするデータ量を抑えながら同様の処理ができるので大量のレコードを処理する際に便利だ。

ただ、以下のコードを見てほしい。


Article.where("id < 100000").order(:id).reverse_order.find_in_batches(batch_size: 1000) do |articles|
  // 適当な処理など...
end

これはArticleテーブルのidが100000以下のレコードを降順で1000件づつ処理しようとしているコードだ。

一見なにも問題ないように見えるこのコードだが、実際に発行されるSQLは以下のような感じになる。

// 1ループ目
SELECT * FROM articles WHERE (id < 100000) AND ORDER BY articles.id DESC LIMIT 1000
// 2ループ目
SELECT * FROM articles WHERE (id < 100000) AND (id > 99000) ORDER BY articles.id ASC LIMIT 1000
// 3ループ目
SELECT * FROM articles WHERE (id < 100000) AND (id > 99001) ORDER BY articles.id ASC LIMIT 1000
...

要は1ループ目以降はorder byが無視されている。

そこでドキュメントを見ると、

NOTE: It's not possible to set the order. That is automatically set to ascending on the primary key (“id ASC”) to make the batch ordering work. This also means that this method only works when the primary key is orderable (e.g. an integer or string).

ということでちゃんとorderが無視されることが書いてある。

したがって、find_in_batchesは降順で処理できないというわけ。

ちゃんと読めということになるが案外見落としがちなので気をつけましょうという話でした。

ちなみにlimitも無視されてbatch_sizeのほうが優先されるので注意。

関連リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1