Skip to content

Instantly share code, notes, and snippets.

@RafaelMCarvalho
Last active September 24, 2015 22:22
Show Gist options
  • Save RafaelMCarvalho/6add6bc57d13c066802d to your computer and use it in GitHub Desktop.
Save RafaelMCarvalho/6add6bc57d13c066802d to your computer and use it in GitHub Desktop.
A concern that adds a perfomatic .bulk_update method for ActiveRecord classes.
module BulkUpdatable
extend ActiveSupport::Concern
self.included do |base|
# Usage:
#
# User.bulk_update([{id: 1, name: 'Foo'}, {id: 2, name: 'Bar'}])
# (1.5ms) UPDATE "users" SET "id" = 1, "name" = 'Foo' WHERE "users"."id" = 1;
# UPDATE "users" SET "id" = 2, "name" = 'Bar' WHERE "users"."id" = 2
# => #<PG::Result:0x007f814aa04c40 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=1>
#
def self.bulk_update(attributes_list)
table = Arel::Table.new(self.table_name)
sql_sets = []
attributes_list.each do |attributes|
update_manager = Arel::UpdateManager.new table.engine
sets = attributes.map { |k, v| [table[k], v] }
update_manager.set(sets).where(table[:id].eq(attributes[:id])).table(table)
sql_sets << update_manager.to_sql
end
ActiveRecord::Base.connection.execute(sql_sets.join(";\n"))
end
end
end
@RafaelMCarvalho
Copy link
Author

Benchmark of 1000 entries updates:

                           user     system      total        real
Simple interator       1.760000   0.620000   2.380000 (  2.985689)
Using transaction      1.200000   0.310000   1.510000 (  1.702462)
Upsert gem             0.150000   0.050000   0.200000 (  0.686520)
BulkUpdatable          0.060000   0.000000   0.060000 (  0.209489)

@RafaelMCarvalho
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment