From 835603899e5df5d9c6d94cdf715e36cade7d02bc Mon Sep 17 00:00:00 2001 From: Ben Dilley Date: Wed, 13 May 2020 15:22:15 +0100 Subject: [PATCH] Grouped query performance of total_count, take 2 Improved performance for total_count on grouped ActiveRecord::Relation. This re-implements #979 using Arel to avoid issues #1012 and #1015 --- .../active_record_relation_methods.rb | 16 +++++++--------- .../active_record_relation_methods_test.rb | 14 +++++++------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/kaminari-activerecord/lib/kaminari/activerecord/active_record_relation_methods.rb b/kaminari-activerecord/lib/kaminari/activerecord/active_record_relation_methods.rb index ed35fbe10..acaa31032 100644 --- a/kaminari-activerecord/lib/kaminari/activerecord/active_record_relation_methods.rb +++ b/kaminari-activerecord/lib/kaminari/activerecord/active_record_relation_methods.rb @@ -32,15 +32,13 @@ def total_count(column_name = :all, _options = nil) #:nodoc: c = c.limit(max_pages * limit_value) if max_pages && max_pages.respond_to?(:*) - # .group returns an OrderedHash that responds to #count - c = c.count(column_name) - @total_count = if c.is_a?(Hash) || c.is_a?(ActiveSupport::OrderedHash) - c.count - elsif c.respond_to? :count - c.count(column_name) - else - c - end + # Handle grouping with a subquery + @total_count = if c.group_values.any? + sq = c.except(:select).select("1 AS record").arel.as("subquery") + c.model.connection.select_value Arel::SelectManager.new.from(sq).project(sq[:record].count) + else + c.count(column_name) + end end # Turn this Relation to a "without count mode" Relation. diff --git a/kaminari-core/test/models/active_record/active_record_relation_methods_test.rb b/kaminari-core/test/models/active_record/active_record_relation_methods_test.rb index 68febbacb..5f7d3cece 100644 --- a/kaminari-core/test/models/active_record/active_record_relation_methods_test.rb +++ b/kaminari-core/test/models/active_record/active_record_relation_methods_test.rb @@ -105,13 +105,13 @@ class ActiveRecordRelationMethodsTest < ActiveSupport::TestCase end test 'calculating STI total_count with GROUP BY clause' do - { - 'Fenton' => Dog, - 'Bob' => Dog, - 'Garfield' => Cat, - 'Bob' => Cat, - 'Caine' => Insect - }.each { |name, type| type.create!(name: name) } + [ + ['Fenton', Dog], + ['Bob', Dog], + ['Garfield', Cat], + ['Bob', Cat], + ['Caine', Insect] + ].each { |name, type| type.create!(name: name) } assert_equal 3, Mammal.group(:name).page(1).total_count end