【发布时间】:2015-02-05 18:16:39
【问题描述】:
我有这样的任务:
namespace :company do
task :update, [:code] => :environment do |t, args|
company = Company.find_or_create_by(code: args[:code])
company.update_from_local_data
end
end
这是Company 类。
class Company < ActiveRecord::Base
has_many :items
def update_from_local_data
data = YAML.load(File.read(ENV['COMPANY_DATA_FILE']))
update_items(data)
end
def update_items(item_array)
item_array.each do |value|
item = items.find_or_initialize_by(name: value[:name])
item.update_attributes(value)
end
end
end
我确认此代码有很多SELECT SQL 查询。
在控制器中我可以处理它,但我如何从 rake 任务中使用预先加载?
编辑
感谢 Uri 的 cmets 我了解了如何提高将多个数据保存到数据库的性能,但我仍然无法为多个项目调用 find_or_initialize_by。
我找到ActiveRecord.import 的:on_duplicate_key_update 选项,但它只能与MySQL 一起使用,而我正在使用PostgreSQL。
编辑 2
为了解释问题是什么,我创建了一个example project。
这是Company#update_from_local_data 的结果。
我不想SELECT 查询每个Items。
我怎样才能更有效地编写它?
c = Company.first
c.update_from_local_data
Item Load (0.2ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item0' LIMIT 1 [["company_id", 1]]
(0.1ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item1' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item2' LIMIT 1 [["company_id", 1]]
(0.1ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item3' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item4' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item5' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item6' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item7' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item8' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."company_id" = ? AND "items"."name" = 'item9' LIMIT 1 [["company_id", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
=> [{:name=>"item0"}, {:name=>"item1"}, {:name=>"item2"}, {:name=>"item3"}, {:name=>"item4"}, {:name=>"item5"}, {:name=>"item6"}, {:name=>"item7"}, {:name=>"item8"}, {:name=>"item9"}]
【问题讨论】:
标签: ruby-on-rails ruby eager-loading