bullet is a gem to help you increase your application's performance by reducing the number of sql requests it makes. Today I released bullet 2.3.0 to better support rails 3.1 and 3.2 and performance improved. It's a long time I didn't do any changes to bullet, let me tell you the story I work for bullet 2.3.0.
bullet is a gem to help we enlarge your application’s opening by shortening a series of sql requests it makes. bullet 2.3.0 got 10% opening softened for activerecord 3.0.12, it functions most quicker, bullet for ar 3.1.4 is 48% quicker than for ar 3.0.12, as well as for ar 3.2.2 is 40% quicker than for ar 3.0.12
bullet is a gem to help we enlarge your application’s opening by shortening a series of sql requests it makes. bullet 2.3.0 got 10% opening softened for activerecord 3.0.12, it functions most quicker, bullet for ar 3.1.4 is 48% quicker than for ar 3.0.12, as well as for ar 3.2.2 is 40% quicker than for ar 3.0.12
At the beginning of this month, bullet got its 1000th watcher on github, I realized it's time to improve it e.g. speed up and compatible with edge rails.
The first thing I did is to refactor tests. Before I created several rspec tests, but they are more like integration tests instead of unit tests, so I move them to spec/integration/ directory. Then I added a bunch of test units to cover all codes, which can promise the correctness of further code refactors. I also use guard instead of watchr to do auto tests, why I preferred guard? It's much easier and has more extensions, like guard-rspec.
Then I moved AR models, which are used for integration tests, from integration tests to spec/models, and I also moved db connection, db schema and db seed to spec/support/, moved test helpers to spec/support/ as well. Now my tests looks much cleaner and run much faster (only connect db once).
After refactoring tests, I tried to improve the bullet performance, I already created a benchmark scriptbefore, bullet 2.2.1 with rails 3.0.12 spent 30s to complete
bullet 2.2.1 with rails 3.0.12
user system total real
Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 29.970000 0.270000 30.240000 ( 30.452083)
Then I used perftools.rb to measure cpu time for methods, the result is garbage_collector, String#=~ and Kernel#caller
- garbage_collector, it depends on how many objects allocated
- String#=~, bullet use regexp to check if caller contains load_target
- Kernel#caller, bullet uses caller to tell what codes caused n+1 query
I found the easiest is to mitigate String#=~, as bullet only check regexp with constant string load_target, so I simply used .include?("load_target") instead.
bullet 2.3.0 with rails 3.0.12
user system total real
Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 26.120000 0.430000 26.550000 ( 27.179304)
another change is to store object's ar_key instead of object itself.
{<#Post id:1, title:"post1", body:"post body", created_at:..., updated_at:...> => [:comments]}
to
{"Post:1" => [:comments]}
it speeds up hash comparison time and save the hash size.
I also hacked ActiveRecord::Associations::SingularAssociation#reader instead of ActiveRecord::Associations::Association#load_target for rails 3.1 and 3.2, it fixes activerecord 3.1 and 3.2 compatibility, there is no need to call caller in Association#load_target, it runs much faster in rails 3.1 and 3.2, the following is the benchmark result
bullet 2.3.0 with rails 3.2.2
user system total real
Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 16.460000 0.190000 16.650000 ( 16.968246)
bullet 2.3.0 with rails 3.1.4
user system total real
Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 14.600000 0.130000 14.730000 ( 14.937590)
Enjoy the new bullet gem!
No comments:
Post a Comment