модуль ActiveRecord::Batches
Публичные методы экземпляра
# File activerecord/lib/active_record/relation/batches.rb, line 48
def find_each(options = {})
if block_given?
find_in_batches(options) do |records|
records.each { |record| yield record }
end
else
enum_for :find_each, options do
options[:start] ? where(table[primary_key].gteq(options[:start])).size : size
end
end
end Перебор коллекции записей из базы данных (например, с помощью метода all) очень неэффективен, поскольку он попытается сразу же создать все объекты.
В этом случае методы пакетной обработки позволяют работать с записями по частям, тем самым значительно уменьшая потребление памяти.
Метод find_each использует find_in_batches с размером пакета 1000 (или как указано в опции :batch_size).
Person.find_each do |person|
person.do_awesome_stuff
end
Person.where("age > 21").find_each do |person|
person.party_all_night!
end
Если вы не передадите блок методу find_each, он вернёт перечислитель для цепочки с другими методами:
Person.find_each.with_index do |person, index| person.award_trophy(index + 1) end
Параметры
-
:batch_size— Указывает размер пакета. По умолчанию 1000. -
:start— Указывает точку начала пакетной обработки.
Это особенно полезно, если несколько рабочих процессов обрабатывают одну и ту же очередь задач. Вы можете настроить рабочий процесс 1 на обработку записей с id от 0 до 10 000, а рабочий процесс 2 — с id от 10 000 и далее (установив параметр :start в этом рабочем процессе).
# Let's process for a batch of 2000 records, skipping the first 2000 rows Person.find_each(start: 2000, batch_size: 2000) do |person| person.party_all_night! end
ПРИМЕЧАНИЕ: Указать порядок невозможно. Он автоматически устанавливается в порядке возрастания по первичному ключу («id ASC»), чтобы обеспечить правильное упорядочение пакетов. Это также означает, что этот метод работает только с первичными ключами на основе целых чисел.
ПРИМЕЧАНИЕ: Также нельзя установить ограничение; оно используется для управления размером пакетов.
# File activerecord/lib/active_record/relation/batches.rb, line 98
def find_in_batches(options = {})
options.assert_valid_keys(:start, :batch_size)
relation = self
start = options[:start]
batch_size = options[:batch_size] || 1000
unless block_given?
return to_enum(:find_in_batches, options) do
total = start ? where(table[primary_key].gteq(start)).size : size
(total - 1).div(batch_size) + 1
end
end
if logger && (arel.orders.present? || arel.taken.present?)
logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
end
relation = relation.reorder(batch_order).limit(batch_size)
records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
while records.any?
records_size = records.size
primary_key_offset = records.last.id
raise "Primary key not included in the custom select clause" unless primary_key_offset
yield records
break if records_size < batch_size
records = relation.where(table[primary_key].gt(primary_key_offset)).to_a
end
end Возвращает каждый пакет записей, найденных методом find options, в виде массива.
Person.where("age > 21").find_in_batches do |group|
sleep(50) # Make sure it doesn't get too crowded in there!
group.each { |person| person.party_all_night! }
end
Если вы не передадите блок методу find_in_batches, он вернёт перечислитель для цепочки с другими методами:
Person.find_in_batches.with_index do |group, batch|
puts "Processing group ##{batch}"
group.each(&:recover_from_last_night!)
end
Для получения каждой записи по отдельности используйте метод find_each.
Параметры
-
:batch_size— Указывает размер пакета. По умолчанию 1000. -
:start— Указывает точку начала пакетной обработки.
Это особенно полезно, если несколько рабочих процессов обрабатывают одну и ту же очередь задач. Вы можете настроить рабочий процесс 1 на обработку записей с id от 0 до 10 000, а рабочий процесс 2 — с id от 10 000 и далее (установив параметр :start в этом рабочем процессе).
# Let's process the next 2000 records
Person.find_in_batches(start: 2000, batch_size: 2000) do |group|
group.each { |person| person.party_all_night! }
end
ПРИМЕЧАНИЕ: Указать порядок невозможно. Он автоматически устанавливается в порядке возрастания по первичному ключу («id ASC»), чтобы обеспечить правильное упорядочение пакетов. Это также означает, что этот метод работает только с первичными ключами на основе целых чисел.
ПРИМЕЧАНИЕ: Также нельзя установить ограничение; оно используется для управления размером пакетов.
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.