Micro-optimize ActiveRecord::Core#hash
Avoids calling _read_attribute("id") more than necessary ```ruby require "active_record" require "benchmark/ips" ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Base.connection.create_table :users do |t| t.text :name end class User < ActiveRecord::Base # This is the current implementation from ActiveRecord::Core def hash if id self.class.hash ^ id.hash else super end end end class UserFastHash < ActiveRecord::Base self.table_name = "users" def hash if i = id self.class.hash ^ i.hash else super end end end 1_000.times { |i| User.create(name: "test #{i}") } slow_users = User.take(1000) fast_users = UserFastHash.take(1000) Benchmark.ips do |x| x.report("slowhash") { hash = {} slow_users.each { |u| hash[u] = 1 } } x.report("fasthash") { hash = {} fast_users.each { |u| hash[u] = 1 } } x.compare! end ``` ``` Warming up -------------------------------------- slowhash 129.000 i/100ms fasthash 177.000 i/100ms Calculating ------------------------------------- slowhash 1.307k (± 0.7%) i/s - 6.579k in 5.033141s fasthash 1.764k (± 2.4%) i/s - 8.850k in 5.021749s Comparison: fasthash: 1763.5 i/s slowhash: 1307.2 i/s - 1.35x (± 0.00) slower ```
This commit is contained in:
parent
7373b5819a
commit
0c25a0baee
@ -601,6 +601,8 @@ def ==(comparison_object)
|
||||
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
||||
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
||||
def hash
|
||||
id = self.id
|
||||
|
||||
if id
|
||||
self.class.hash ^ id.hash
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user