Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevingriffin/29d7e4774d210a41116c063dfd430de0 to your computer and use it in GitHub Desktop.
Save kevingriffin/29d7e4774d210a41116c063dfd430de0 to your computer and use it in GitHub Desktop.
## Results:
## CollectionProxies (1000000): 30.980000 2.890000 33.870000 ( 33.993120)
## Associations (1000000): 0.120000 0.000000 0.120000 ( 0.120288)
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