From a91610f530988691836a307df88a152ed6239554 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 11 Jan 2022 16:04:14 +0100 Subject: [PATCH] Optimized multiple DB queries --- CHANGELOG.md | 1 + Gemfile | 1 + Gemfile.lock | 7 ++++++- app/controllers/api/notifications_controller.rb | 7 +++++-- app/controllers/application_controller.rb | 9 +++++++++ app/models/payment_schedule.rb | 2 +- app/services/invoices_service.rb | 2 +- app/services/payment_schedule_service.rb | 2 +- config/environments/development.rb | 11 +++++++++++ 9 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef2b5918..f1498e4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Update events heading style - Update some icons - Optimized the load time of the payment schedules list +- Optimized multiple DB queries - Fix a bug: do not load Stripe if no keys were defined - Fix a bug: some links redirect to the home page instead of triggering the requested action - Fix a bug: exports to Excel are corrupted (#49) diff --git a/Gemfile b/Gemfile index 85a7fb58f..f80408e12 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'active_record_query_trace' gem 'awesome_print' + gem 'bullet' gem 'coveralls_reborn', '~> 0.18.0', require: false gem 'foreman' gem 'web-console', '>= 3.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 932f16792..312eac6ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,6 +67,9 @@ GEM bootsnap (1.4.6) msgpack (~> 1.0) builder (3.2.4) + bullet (7.0.0) + activesupport (>= 3.0.0) + uniform_notifier (~> 1.11) camertron-eprun (1.1.1) carrierwave (2.1.1) activemodel (>= 5.0.0) @@ -394,6 +397,7 @@ GEM tzinfo-data (1.2020.4) tzinfo (>= 1.0.0) unicode-display_width (1.4.1) + uniform_notifier (1.14.2) vcr (6.0.0) virtus (1.0.5) axiom-types (~> 0.1) @@ -431,6 +435,7 @@ DEPENDENCIES apipie-rails awesome_print bootsnap + bullet carrierwave caxlsx caxlsx_rails @@ -498,4 +503,4 @@ DEPENDENCIES webpacker (~> 5.x) BUNDLED WITH - 2.1.4 + 2.2.19 diff --git a/app/controllers/api/notifications_controller.rb b/app/controllers/api/notifications_controller.rb index 71cf9be71..a77a55e0a 100644 --- a/app/controllers/api/notifications_controller.rb +++ b/app/controllers/api/notifications_controller.rb @@ -6,12 +6,15 @@ class API::NotificationsController < API::ApiController include NotifyWith::NotificationsApi before_action :authenticate_user! + # notifications can have anything attached, so we won't eager load the whole database + around_action :skip_bullet, if: -> { defined?(Bullet) } + # Number of notifications added to the page when the user clicks on 'load next notifications' NOTIFICATIONS_PER_PAGE = 15 def index loop do - @notifications = current_user.notifications.page(params[:page]).per(NOTIFICATIONS_PER_PAGE).order('created_at DESC') + @notifications = current_user.notifications.includes(:attached_object).page(params[:page]).per(NOTIFICATIONS_PER_PAGE).order('created_at DESC') # we delete obsolete notifications on first access break unless delete_obsoletes(@notifications) end @@ -24,7 +27,7 @@ class API::NotificationsController < API::ApiController def last_unread loop do - @notifications = current_user.notifications.where(is_read: false).limit(3).order('created_at DESC') + @notifications = current_user.notifications.includes(:attached_object).where(is_read: false).limit(3).order('created_at DESC') # we delete obsolete notifications on first access break unless delete_obsoletes(@notifications) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2077f304a..1301763bd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -80,4 +80,13 @@ class ApplicationController < ActionController::Base def authenticate_user! super end + + # N+1 query detection (https://github.com/flyerhzm/bullet) + def skip_bullet + previous_value = Bullet.enable? + Bullet.enable = false + yield + ensure + Bullet.enable = previous_value + end end diff --git a/app/models/payment_schedule.rb b/app/models/payment_schedule.rb index 749e31d9e..ae231d2a6 100644 --- a/app/models/payment_schedule.rb +++ b/app/models/payment_schedule.rb @@ -50,7 +50,7 @@ class PaymentSchedule < PaymentDocument end def gateway_subscription - payment_gateway_objects.map(&:gateway_object).find(&:subscription?) + payment_gateway_objects.includes(:payment_gateway_object).map(&:gateway_object).find(&:subscription?) end def gateway_order diff --git a/app/services/invoices_service.rb b/app/services/invoices_service.rb index 4d207545b..7d36fbb38 100644 --- a/app/services/invoices_service.rb +++ b/app/services/invoices_service.rb @@ -9,7 +9,7 @@ class InvoicesService # @param size {number} number of items per page # @param filters {Hash} allowed filters: number, customer, date. def self.list(order_key, direction, page, size, filters = {}) - invoices = Invoice.includes(:avoir, :invoicing_profile, invoice_items: %i[subscription invoice_item]) + invoices = Invoice.includes(:avoir, :operator_profile, :payment_gateway_object, invoicing_profile: [:user]) .joins(:invoicing_profile) .order("#{order_key} #{direction}") .page(page) diff --git a/app/services/payment_schedule_service.rb b/app/services/payment_schedule_service.rb index 1acc8ef8c..97d3748da 100644 --- a/app/services/payment_schedule_service.rb +++ b/app/services/payment_schedule_service.rb @@ -127,7 +127,7 @@ class PaymentScheduleService # @param filters {Hash} allowed filters: reference, customer, date. ## def self.list(page, size, filters = {}) - ps = PaymentSchedule.includes(:invoicing_profile, :payment_schedule_items, :payment_schedule_objects) + ps = PaymentSchedule.includes(:operator_profile, :payment_schedule_items, invoicing_profile: [:user]) .joins(:invoicing_profile) .order('payment_schedules.created_at DESC') .page(page) diff --git a/config/environments/development.rb b/config/environments/development.rb index ef91765f0..2de9cb7eb 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,6 +1,17 @@ # frozen_string_literal: true Rails.application.configure do + # https://github.com/flyerhzm/bullet + # In development, Bullet will find and report N+1 DB requests + config.after_initialize do + Bullet.enable = true + Bullet.alert = true + Bullet.bullet_logger = true + Bullet.console = true + Bullet.rails_logger = true + Bullet.add_footer = true + end + # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on