Избегайте N + 1 запроса в большом наборе данных - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть миграция, которая обновляет существующие записи с новым значением атрибута.Модель называется «MyRecord».В базе данных содержатся миллионы записей с новым столбцом unit_id, равным нулю.Я хочу обновить этот столбец unit_id определенным значением:

MyRecord.find_each do |record|
  unit_id = Unit.calculate_unit_from_old_columns(record.legacy_column_1, record.legacy_column_2).first.id
  record.update unit_id: unit_id
end

. Это создает множество запросов N + 1:

SELECT units.* FROM units WHERE units.item_1 = 'Electronics' AND units.item_2 = 'Auto' 
UPDATE my_records SET unit_id='43' WHERE legacy_column_1 = 'Legacy Electronics' AND legacy_column_2 = 'Legacy Auto';

И некоторые из этих запросов N + 1 дублируются.,Я вижу многое из этого в журналах:

SELECT units.* FROM units WHERE units.item_1 = 'Electronics' AND units.item_2 = 'Auto' 
SELECT units.* FROM units WHERE units.item_1 = 'Electronics' AND units.item_2 = 'Auto' 

Я знаком с готовой загрузкой через include.Но когда эта миграция будет запущена для обновления существующих данных, ассоциации еще не будет.Поэтому я не могу сделать это:

record.includes(:unit)

Как я могу исключить N + 1 запросов и кэшировать запрос, чтобы он не попадал снова в базу данных при повторном запросе?

1 Ответ

0 голосов
/ 15 ноября 2018

Используйте простой запрос, вы можете подумать о его пакетировании, если он выполняется слишком долго:

MyRecord.connection.execute(
  "UPDATE my_records, units 
   SET unit_id = units.id 
   WHERE units.item_1 = legacy_column_1 AND units.item_2 = legacy_column_2"
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...