Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AR Performance regression in 3.1 #1717

Closed
paul opened this issue Jun 15, 2011 · 4 comments
Closed

AR Performance regression in 3.1 #1717

paul opened this issue Jun 15, 2011 · 4 comments
Assignees

Comments

@paul
Copy link
Contributor

paul commented Jun 15, 2011

>> require 'active_record'
=> true
>> ActiveRecord::Base.establish_connection(
?>       :adapter => "sqlite3",
?>       :database  => "benchmark.db"
>>   )
>> ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS active_record_models")
>> ActiveRecord::Base.connection.execute("CREATE TABLE active_record_models (id INTEGER UNIQUE, title STRING, text STRING)")
>> class ActiveRecordModel < ActiveRecord::Base
>>   end
>> ActiveRecordModel.new
>> require 'benchmark'

#3.0.7

>> Benchmark.measure { 100_000.times { ActiveRecordModel.new } }
=>   1.470000   0.000000   1.470000   1.474953

#3.1.0.rc4

>> Benchmark.measure { 100_000.times { ActiveRecordModel.new } }
=>   7.910000   0.050000   7.960000   7.951169

>> Benchmark.measure { 100_000.times { ActiveRecordModel.new(:title => "foo", :text => "bar") } }
=>  15.380000   0.010000  15.390000  15.381160

https://gist.github.com/fabfaf1bd8503fbf6d32

@ghost ghost assigned tenderlove Jun 15, 2011
@jhawthorn
Copy link
Member

About half of the runtime looks to be from the apply_default_scope assignment introduced in c69111b, which @jonleighton has said he would be changing.

@jonleighton
Copy link
Member

Thanks @jhawthorn. I did mean to fix that, not sure how it escaped my attention. Have pushed a fix now, but leaving this open as master is still about twice as slow as 3-0-stable.

@tenderlove
Copy link
Member

Just to update this, it looks like we're making more (greater than 0) calls to scoped in 3.1. I'm looking in to this, but here are the perf graphs in the mean time.

Graph of 3.0:
3.0 graph

Graph of 3.1:

3.1 graph

Edit: added links to larger images.

@tenderlove
Copy link
Member

I think we can close this now. I used this script for benchmarking:

require 'active_record'
require 'benchmark'

p ActiveRecord::VERSION::STRING

ActiveRecord::Base.establish_connection(
  :adapter  => "sqlite3",
  :database => ":memory:"
)

ActiveRecord::Base.connection.execute("CREATE TABLE active_record_models (id INTEGER UNIQUE, title STRING, text STRING)")

class ActiveRecordModel < ActiveRecord::Base; end
ActiveRecordModel.new

N = 100_000
Benchmark.bm { |x| x.report('new') { N.times { ActiveRecordModel.new } } }

I got these results:

[aaron@higgins activerecord (3-1-stable)]$ ruby -I lib test.rb
"3.1.0.rc4"
      user     system      total        real
new  2.500000   0.010000   2.510000 (  2.527923)
[aaron@higgins activerecord (3-0-stable)]$ ruby -I lib test.rb
"3.0.9"
      user     system      total        real
new  2.490000   0.020000   2.510000 (  2.535049)

Times would vary slightly. Sometimes 3.1.0 would be faster, sometimes not. They are approximately the same speed, so I think we can close this ticket.

A few interesting things:

  • Asking for scope is very expensive. That is a major reason for the performance problems in this ticket. Creating AR objects within a scope will still be quite slow compared to non scope creation (but I think this is true for 3.0 too).
  • 3.1.0 creates 7 hashes per AR object where 3.0.x creates 4 (we have new caches in 3.1)
  • 3.1.0 makes more method calls from AR::Base#initialize
  • Some of these performance improvement commits could be applied to 3.0.x too

It took these commits to bring the time down:

e0fae72 remove useless assignment
d864616 lock_optimistically is typically true, so evaluate the common failure case first
558b5bb reduce object allocation during AR instantiation
196f92f remove the check for needs_type_condition? because ensure_proper_type will pick up the type column
992b3b5 stop using && for the short circuit side effect
5d954b4 let strings be converted to symbols inside the interpreter
9fd0d91 avoice paying hash cost if there are no serialized attributes
2fe088a cache column defaults for AR object instantiation
b927f0a AR object instantiation is ~30% faster in the simple case
0de56aa initialize instance variables
3a14e6f oops! remove debugging codes
0abb7b8 default create_with_value to a hash so we can eliminate conditionals, add test surrounding create_with(nil) behavior

@paul thank you for reporting this issue. I appreciate it! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants