Rails 创建单条记录 VS 创建多条记录 性能差异
Rails create single record VS create multiple records PERFOMANCE difference
这两种方法有速度差异吗? (POSTGRESQL)
第一个
products = [{...},{...},...]
products.each { |p|
Product.create(p)
}
第二
products = [{...},{...},...]
Product.create(products)
每条记录的两种方法都会进行两次查询:
1) INSERT INTO "products" VALUES (..)
2) UPDATE "products" SET "updated_at"...
两者在性能方面应该几乎没有差异。
如果检查 the implementation,您会发现如果将数组传递给 .create
,它会遍历数组并为数组中的每个元素调用 .create
。
module ActiveRecord
module Persistence
extend ActiveSupport::Concern
module ClassMethods
# ...
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save
object
end
end
# ...
end
end
ActiveRecord 实际上并没有实现批量插入。我的意思是在单个语句中插入多行:
INSERT INTO products (name, description) VALUES ('Soap', '100% whale based.'),('Shampoo', '...')
如果有足够的记录,速度可以提高一个数量级。
但您可以编写自己的 SQL 来完成此操作:
class Product
def self.mass_insert(attributes)
values = products.map("(#{attributes[:name]}, #{attributes[:description]})").join(',')
self.connection.execute("INSERT INTO products (name, description) VALUES #{values}")
end
end
请注意,这个简单的示例不会对输入进行清理,并且容易受到 SQL 注入攻击。
max 是对的。是本地解决方案。
但我发现 activerecord-import
gem 做同样的事情 - 批量对象导入。
这两种方法有速度差异吗? (POSTGRESQL)
第一个
products = [{...},{...},...]
products.each { |p|
Product.create(p)
}
第二
products = [{...},{...},...]
Product.create(products)
每条记录的两种方法都会进行两次查询:
1) INSERT INTO "products" VALUES (..)
2) UPDATE "products" SET "updated_at"...
两者在性能方面应该几乎没有差异。
如果检查 the implementation,您会发现如果将数组传递给 .create
,它会遍历数组并为数组中的每个元素调用 .create
。
module ActiveRecord
module Persistence
extend ActiveSupport::Concern
module ClassMethods
# ...
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save
object
end
end
# ...
end
end
ActiveRecord 实际上并没有实现批量插入。我的意思是在单个语句中插入多行:
INSERT INTO products (name, description) VALUES ('Soap', '100% whale based.'),('Shampoo', '...')
如果有足够的记录,速度可以提高一个数量级。
但您可以编写自己的 SQL 来完成此操作:
class Product
def self.mass_insert(attributes)
values = products.map("(#{attributes[:name]}, #{attributes[:description]})").join(',')
self.connection.execute("INSERT INTO products (name, description) VALUES #{values}")
end
end
请注意,这个简单的示例不会对输入进行清理,并且容易受到 SQL 注入攻击。
max 是对的。是本地解决方案。
但我发现 activerecord-import
gem 做同样的事情 - 批量对象导入。