From 2c78c7f4cdb1fae2650563f80feb294d2b7e5d80 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 4 Jul 2017 17:08:41 +0000 Subject: [PATCH] Revert "Merge branch 'revert-12499' into 'master'" This reverts merge request !12557 --- app/controllers/projects/issues_controller.rb | 2 +- app/models/concerns/sortable.rb | 23 +++++++++++++++++++ app/models/project.rb | 6 ++--- ...drop-default-scope-on-sortable-finders.yml | 4 ++++ spec/models/concerns/sortable_spec.rb | 21 +++++++++++++++++ 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/dm-drop-default-scope-on-sortable-finders.yml create mode 100644 spec/models/concerns/sortable_spec.rb diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index ca483c105b6..54f108353cd 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -227,7 +227,7 @@ class Projects::IssuesController < Projects::ApplicationController def issue return @issue if defined?(@issue) # The Sortable default scope causes performance issues when used with find_by - @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take! + @noteable = @issue ||= @project.issues.find_by!(iid: params[:id]) return render_404 unless can?(current_user, :read_issue, @issue) diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index a155a064032..fdacfa5a194 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -5,6 +5,25 @@ module Sortable extend ActiveSupport::Concern + module DropDefaultScopeOnFinders + # Override these methods to drop the `ORDER BY id DESC` default scope. + # See http://dba.stackexchange.com/a/110919 for why we do this. + %i[find find_by find_by!].each do |meth| + define_method meth do |*args, &block| + return super(*args, &block) if block + + unordered_relation = unscope(:order) + + # We cannot simply call `meth` on `unscope(:order)`, since that is also + # an instance of the same relation class this module is included into, + # which means we'd get infinite recursion. + # We explicitly use the original implementation to prevent this. + original_impl = method(__method__).super_method.unbind + original_impl.bind(unordered_relation).call(*args) + end + end + end + included do # By default all models should be ordered # by created_at field starting from newest @@ -18,6 +37,10 @@ module Sortable scope :order_updated_asc, -> { reorder(updated_at: :asc) } scope :order_name_asc, -> { reorder(name: :asc) } scope :order_name_desc, -> { reorder(name: :desc) } + + # All queries (relations) on this model are instances of this `relation_klass`. + relation_klass = relation_delegate_class(ActiveRecord::Relation) + relation_klass.prepend DropDefaultScopeOnFinders end module ClassMethods diff --git a/app/models/project.rb b/app/models/project.rb index 241e7e60dd2..8e9e42d28ab 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -815,7 +815,7 @@ class Project < ActiveRecord::Base end def ci_service - @ci_service ||= ci_services.reorder(nil).find_by(active: true) + @ci_service ||= ci_services.find_by(active: true) end def deployment_services @@ -823,7 +823,7 @@ class Project < ActiveRecord::Base end def deployment_service - @deployment_service ||= deployment_services.reorder(nil).find_by(active: true) + @deployment_service ||= deployment_services.find_by(active: true) end def monitoring_services @@ -831,7 +831,7 @@ class Project < ActiveRecord::Base end def monitoring_service - @monitoring_service ||= monitoring_services.reorder(nil).find_by(active: true) + @monitoring_service ||= monitoring_services.find_by(active: true) end def jira_tracker? diff --git a/changelogs/unreleased/dm-drop-default-scope-on-sortable-finders.yml b/changelogs/unreleased/dm-drop-default-scope-on-sortable-finders.yml new file mode 100644 index 00000000000..b359a25053a --- /dev/null +++ b/changelogs/unreleased/dm-drop-default-scope-on-sortable-finders.yml @@ -0,0 +1,4 @@ +--- +title: Improve performance of lookups of issues, merge requests etc by dropping unnecessary ORDER BY clause +merge_request: +author: diff --git a/spec/models/concerns/sortable_spec.rb b/spec/models/concerns/sortable_spec.rb new file mode 100644 index 00000000000..d1e17c4f684 --- /dev/null +++ b/spec/models/concerns/sortable_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Sortable do + let(:relation) { Issue.all } + + describe '#where' do + it 'orders by id, descending' do + order_node = relation.where(iid: 1).order_values.first + expect(order_node).to be_a(Arel::Nodes::Descending) + expect(order_node.expr.name).to eq(:id) + end + end + + describe '#find_by' do + it 'does not order' do + expect(relation).to receive(:unscope).with(:order).and_call_original + + relation.find_by(iid: 1) + end + end +end -- GitLab