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

Performance issues when using preload with large number of rows #616

Open
iSarCasm opened this issue Feb 8, 2022 · 2 comments
Open

Performance issues when using preload with large number of rows #616

iSarCasm opened this issue Feb 8, 2022 · 2 comments

Comments

@iSarCasm
Copy link

iSarCasm commented Feb 8, 2022

Issue

There is a performance issue when using preload for a large number of rows. Even though, the request itself may be very fast there is a very large amount of time spent in the Bullet::Rack part. Example code:

@comments = Comment.preload(:article).first(5_000)

With bullet turned OFF:

Completed 200 OK in 652ms (Views: 409.3ms | ActiveRecord: 60.8ms | Allocations: 807853)

Request completed in ~0.6 seconds
vnd m  Other

Ruby-Prof flat output:

Measure Mode: wall_time
Thread ID: 14120
Fiber ID: 15100
Total: 1.916769
Sort by: self_time

 %self      total      self      wait     child     calls  name                           location
 16.54      0.317     0.317     0.000     0.000    10020   IO#write                       
  4.06      0.078     0.078     0.000     0.000        9   PG::Result#values              
  3.07      1.916     0.059     0.000     1.857    71567  *Array#each                     
  2.13      0.041     0.041     0.000     0.000        1   PG::Connection#exec_params     
  1.57      0.433     0.030     0.000     0.403    15020   ActiveSupport::LoggerThreadSafeLevel#add /Users/igortsykalo/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/activesupport-7.0.1/lib/active_support/logger_thread_safe_level.rb:50
  1.56      0.186     0.030     0.000     0.156    70719  *Class#new                      
  1.50      0.078     0.029     0.000     0.049   125484  *Hash#fetch                     
  1.26      0.070     0.024     0.000     0.046    35000   ActiveRecord::AttributeMethods#respond_to? /Users/igortsykalo/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/activerecord-7.0.1/lib/active_record/attribute_methods.rb:207
  1.15      0.022     0.022     0.000     0.000        7   PG::Connection#async_exec      
  1.14      0.022     0.022     0.000     0.000   169832   Module#===                     
  1.08      0.023     0.021     0.000     0.003       43   <Module::Bootsnap::CompileCache::Native>#fetch 

Full profiling information can be found here: https://github.com/iSarCasm/bullet-performance-app/tree/main/rubyprof

With bullet turned ON:

Completed 200 OK in 1095ms (Views: 643.1ms | ActiveRecord: 60.2ms | Allocations: 1857914)

Request completed in ~10 seconds
Pasted Graphic

Ruby-Prof flat output:

Measure Mode: wall_time
Thread ID: 14340
Fiber ID: 15100
Total: 45.175374
Sort by: self_time

 %self      total      self      wait     child     calls  name                           location
 21.73     16.381     9.816     0.000     6.565 25000015   Set#merge                      /Users/igortsykalo/.rbenv/versions/2.7.5/lib/ruby/2.7.0/set.rb:422
 19.01     39.600     8.589     0.000    31.010   276582  *Array#each                     
 11.75      8.288     5.309     0.000     2.980 25005000   <Class::Bullet::Detector::Association>#call_object_associations /Users/igortsykalo/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/bullet-7.0.1/lib/bullet/detector/association.rb:62
  7.68      3.469     3.469     0.000     0.000 25005000   Bullet::Registry::Base#[]      /Users/igortsykalo/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/bullet-7.0.1/lib/bullet/registry/base.rb:12
  6.97      4.516     3.151     0.000     1.365    25079  *Array#hash                     
  4.70      2.121     2.121     0.000     0.000 25000004   Hash#update                    
  3.71      1.675     1.674     0.000     0.000 25100087   Thread#[]                      
  3.59      1.622     1.622     0.000     0.000 25005027   Kernel#instance_of?            
  3.22      1.453     1.453     0.000     0.000 25010014   Kernel#instance_variable_get   
  3.18      1.434     1.434     0.000     0.000 26205193   Kernel#class                   
  3.01      1.360     1.359     0.000     0.000 25025185   String#hash                    
  2.93      1.324     1.324     0.000     0.000 25170467   <Class::Thread>#current        
  1.56      0.706     0.706     0.000     0.000     5014   Array#flatten   

Full profiling information can be found here: https://github.com/iSarCasm/bullet-performance-app/tree/main/rubyprof

Steps to reproduce

I have created a sample Rails 7 application with 2 scaffolded models and a seed file hosted here: https://github.com/iSarCasm/bullet-performance-app

It also mentions the full list of steps taken to recreate the problem.

Possible problem

This is probably caused by the UnusedEagerLoading detector (https://github.com/flyerhzm/bullet/blob/master/lib/bullet/detector/unused_eager_loading.rb) which seems to have O(n^2) time complexity since there are 25000015 Set#merge invocation which is ~5000*5000 (5000 Comments with 5000 Articles loaded in 2 DB queries).

@iSarCasm iSarCasm changed the title Performance issues when using preload on large amounts of rows Performance issues when using preload on large number of rows Feb 8, 2022
@iSarCasm iSarCasm changed the title Performance issues when using preload on large number of rows Performance issues when using preload with large number of rows Feb 8, 2022
@dsantosmerino
Copy link

Thanks @iSarCasm for sharing this. We are having a similar performance issue for a large amount of records query. In our case it seems like the issue is with the N + 1 query detector.

@camilova
Copy link
Contributor

camilova commented Dec 6, 2022

It could be related to #623 too.

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

3 participants