bensheldon / good_job

Multithreaded, Postgres-based, Active Job backend for Ruby on Rails.
https://goodjob-demo.herokuapp.com/
MIT License
2.65k stars 195 forks source link

[Enhance] Enhance performance via counter cache #1375

Closed hotrungnhan closed 2 months ago

hotrungnhan commented 3 months ago

https://github.com/flyerhzm/bullet

When i install good_jobs in my project, and try with the dash board. Bullet has told me that we can improved the performance of GJ by using counter cache.

It alert on:

bensheldon commented 3 months ago

Can you share the query that you're seeing from Bullet? I'm curious if you can give a few more details about where in GoodJob it's causing N+1s.

Generally I try to avoid counter-caches in GoodJob because frequently jobs are added or deleted without invoking Active Record callbacks (for performance). But there shouldn't be N+1s.

hotrungnhan commented 3 months ago

it in batch page of dashboard, it count jobs for each batch which lead to N+1. @bensheldon if It a performance pain if we use CC for that case. i suggest we can using an short term cache when the total of jobs is huge such:

hotrungnhan commented 3 months ago
Screenshot 2024-06-18 at 09 43 15
jamesst20 commented 2 months ago

https://github.com/flyerhzm/bullet

When i install good_jobs in my project, and try with the dash board. Bullet has told me that we can improved the performance of GJ by using counter cache.

It alert on:

* `GoodJob::BatchRecord` on `jobs` relationship

Hi, I am not using batch or a maintainer but maybe as a workaround while this gets checked out you could try a gem like goldiloader to handle N+1 automatically for you. You can enable it per request as such

      prepend_around_action :set_request_eager_loading, if: -> {...something like controller_path == "good_job/..." }

      private

      def set_request_eager_loading(&block)
        Goldiloader.enabled(&block)
      end

Let me know if it helps! This saved me a few times :)

bensheldon commented 2 months ago

I looked into this:

Here's the controller, which has a filter object:

https://github.com/bensheldon/good_job/blob/17d3369a2b52ff643a58b38f67e233778f74fe9a/app/controllers/good_job/batches_controller.rb#L6

The filter object does have an includes(:jobs), so it should be preloaded:

https://github.com/bensheldon/good_job/blob/17d3369a2b52ff643a58b38f67e233778f74fe9a/app/filters/good_job/batches_filter.rb#L19

Nuts! In the template it calls jobs.count which always emits a query, whereas it should be jobs.size 🤦 :

https://github.com/bensheldon/good_job/blob/17d3369a2b52ff643a58b38f67e233778f74fe9a/app/views/good_job/batches/_table.erb#L59