我有一个迁移,它使用新的属性值更新现有记录。该模型称为“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'
我熟悉通过包含进行急切加载。但是,当运行此迁移来更新现有数据时,将不会有任何关联。所以我不能这样做:
record.includes(:unit)
如何消除 N+1 查询并缓存查询,以便在重复查询时不会再次访问数据库?
最佳答案
使用简单的查询,如果运行时间太长,可以考虑批处理:
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"
)
关于mysql - 避免大数据集中的N+1查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53309663/