Created
February 16, 2017 08:44
-
-
Save chrisandreae/97a22402b08290de7702185a823765e8 to your computer and use it in GitHub Desktop.
CollectionProxy speed test case
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Iterates a tree of a million preloaded ActiveRecord objects, using | |
## either the association CollectionProxy or `association(:foo).target`. | |
## Results: | |
## CollectionProxies (1000000): 31.230000 2.040000 33.270000 ( 33.840189) | |
## Associations (1000000): 0.130000 0.000000 0.130000 ( 0.122716) | |
require 'active_record' | |
require 'sqlite3' | |
require 'benchmark' | |
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:" | |
ActiveRecord::Schema.define do | |
create_table(:as) do |t| | |
end | |
create_table(:bs) do |t| | |
t.references :a | |
end | |
create_table(:cs) do |t| | |
t.references :b | |
end | |
create_table(:ds) do |t| | |
t.references :c | |
end | |
end | |
class A < ActiveRecord::Base | |
has_many :bs, inverse_of: :a, dependent: :destroy | |
end | |
class B < ActiveRecord::Base | |
belongs_to :a, inverse_of: :bs | |
has_many :cs, inverse_of: :b, dependent: :destroy | |
end | |
class C < ActiveRecord::Base | |
belongs_to :b, inverse_of: :cs | |
has_many :ds, inverse_of: :c, dependent: :destroy | |
end | |
class D < ActiveRecord::Base | |
belongs_to :c, inverse_of: :ds | |
end | |
# Make a tree of a million records and iterate it. | |
ActiveRecord::Base.connection.execute("create temporary table ten (integer)") | |
ActiveRecord::Base.connection.execute("insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)") | |
ActiveRecord::Base.connection.execute("insert into \"as\" select null from ten join ten") | |
ActiveRecord::Base.connection.execute("insert into \"bs\" (a_id) select id from \"as\" join ten join ten") | |
ActiveRecord::Base.connection.execute("insert into \"cs\" (b_id) select id from \"bs\" join ten") | |
ActiveRecord::Base.connection.execute("insert into \"ds\" (c_id) select id from \"cs\" join ten") | |
def traverse_collection_proxies(as) | |
count = 0 | |
as.each do |a| | |
a.bs.each do |b| | |
b.cs.each do |c| | |
c.ds.each do | |
count += 1 | |
end | |
end | |
end | |
end | |
count | |
end | |
def traverse_associations(as) | |
count = 0 | |
as.each do |a| | |
a.association(:bs).target.each do |b| | |
b.association(:cs).target.each do |c| | |
c.association(:ds).target.each do | |
count += 1 | |
end | |
end | |
end | |
end | |
count | |
end | |
def without_gc | |
GC.start | |
GC.disable | |
yield | |
GC.enable | |
end | |
loaded = A.includes(:bs => { :cs => :ds }).to_a | |
without_gc do | |
count = nil | |
bm = Benchmark.measure { count = traverse_collection_proxies(loaded) } | |
puts "CollectionProxies (#{count}): #{bm}" | |
end | |
loaded = A.includes(:bs => { :cs => :ds }).to_a | |
without_gc do | |
count = nil | |
bm = Benchmark.measure { count = traverse_associations(loaded) } | |
puts "Associations (#{count}): #{bm}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment