require 'benchmark/ips' ActiveRecord::Base.logger = nil def pagy_count(collection) (c = collection.count(:all)).is_a?(Hash) ? c.size : c end def pagy_count2(collection) result = collection.count(:all) collection.group_values.empty? ? result : result.size end def pagy_count3(collection) if collection.group_values.empty? collection.count(:all) else collection.count(:all).size end end def pagy_arel_count(collection) # COUNT(*) OVER () sql = Arel.star.count.over(Arel::Nodes::Grouping.new([])) collection.unscope(:order).limit(1).pluck(sql).first end def pagy_arel_conditional_count(collection) if collection.group_values.empty? # COUNT(*) collection.count(:all) else # COUNT(*) OVER () sql = Arel.star.count.over(Arel::Nodes::Grouping.new([])) collection.unscope(:order).limit(1).pluck(sql).first end end collection = ::Movies::Rating.all Benchmark.ips do |x| x.time = 30 x.report("pagy_count:") { ApplicationRecord.uncached { pagy_count(collection) } } x.report("pagy_count2:") { ApplicationRecord.uncached { pagy_count2(collection) } } x.report("pagy_count3:") { ApplicationRecord.uncached { pagy_count3(collection) } } x.report("pagy_arel_count:") { ApplicationRecord.uncached { pagy_arel_count(collection) } } x.report("pagy_arel_conditional_count:") { ApplicationRecord.uncached { pagy_arel_conditional_count(collection) } } x.compare! end <<-OUTPUT Warming up -------------------------------------- pagy_count: 2.000 i/100ms pagy_count2: 1.000 i/100ms pagy_count3: 2.000 i/100ms pagy_arel_count: 1.000 i/100ms pagy_arel_conditional_count: 2.000 i/100ms Calculating ------------------------------------- pagy_count: 26.297 (±19.0%) i/s - 758.000 in 30.060235s pagy_count2: 30.137 (±26.5%) i/s - 849.000 in 30.005502s pagy_count3: 31.145 (±16.1%) i/s - 912.000 in 30.055667s pagy_arel_count: 7.863 (±12.7%) i/s - 227.000 in 30.119870s pagy_arel_conditional_count: 27.263 (±22.0%) i/s - 762.000 in 30.013175s Comparison: pagy_count3:: 31.1 i/s pagy_count2:: 30.1 i/s - same-ish: difference falls within error pagy_arel_conditional_count:: 27.3 i/s - same-ish: difference falls within error pagy_count:: 26.3 i/s - same-ish: difference falls within error pagy_arel_count:: 7.9 i/s - 3.96x slower OUTPUT collection = ::Movies::Rating.group(:movie_id).select(:movie_id) # 1682 movies Benchmark.ips do |x| x.time = 30 x.report("pagy_count:") { ApplicationRecord.uncached { pagy_count(collection) } } x.report("pagy_count2:") { ApplicationRecord.uncached { pagy_count2(collection) } } x.report("pagy_count3:") { ApplicationRecord.uncached { pagy_count3(collection) } } x.report("pagy_arel_count:") { ApplicationRecord.uncached { pagy_arel_count(collection) } } x.report("pagy_arel_conditional_count:") { ApplicationRecord.uncached { pagy_arel_conditional_count(collection) } } x.compare! end <<-OUTPUT Warming up -------------------------------------- pagy_count: 1.000 i/100ms pagy_count2: 1.000 i/100ms pagy_count3: 1.000 i/100ms pagy_arel_count: 1.000 i/100ms pagy_arel_conditional_count: 1.000 i/100ms Calculating ------------------------------------- pagy_count: 5.874 (±34.0%) i/s - 166.000 in 30.288133s pagy_count2: 9.154 (±21.8%) i/s - 256.000 in 30.024894s pagy_count3: 9.811 (±20.4%) i/s - 278.000 in 30.101955s pagy_arel_count: 8.969 (±33.5%) i/s - 249.000 in 30.070671s pagy_arel_conditional_count: 12.439 (±24.1%) i/s - 351.000 in 30.087875s Comparison: pagy_arel_conditional_count:: 12.4 i/s pagy_count3:: 9.8 i/s - same-ish: difference falls within error pagy_count2:: 9.2 i/s - same-ish: difference falls within error pagy_arel_count:: 9.0 i/s - same-ish: difference falls within error pagy_count:: 5.9 i/s - 2.12x slower OUTPUT collection = ::Movies::Rating.group(:rating).select(:rating) # 5 ratings (1,2,3,4,5) Benchmark.ips do |x| x.time = 30 x.report("pagy_count:") { ApplicationRecord.uncached { pagy_count(collection) } } x.report("pagy_count2:") { ApplicationRecord.uncached { pagy_count2(collection) } } x.report("pagy_count3:") { ApplicationRecord.uncached { pagy_count3(collection) } } x.report("pagy_arel_count:") { ApplicationRecord.uncached { pagy_arel_count(collection) } } x.report("pagy_arel_conditional_count:") { ApplicationRecord.uncached { pagy_arel_conditional_count(collection) } } x.compare! end <<-OUTPUT Warming up -------------------------------------- pagy_count: 1.000 i/100ms pagy_count2: 1.000 i/100ms pagy_count3: 1.000 i/100ms pagy_arel_count: 1.000 i/100ms pagy_arel_conditional_count: 1.000 i/100ms Calculating ------------------------------------- pagy_count: 7.855 (±25.5%) i/s - 224.000 in 30.015308s pagy_count2: 9.501 (±21.1%) i/s - 271.000 in 30.038578s pagy_count3: 9.978 (±20.0%) i/s - 288.000 in 30.018907s pagy_arel_count: 11.988 (±25.0%) i/s - 342.000 in 30.003528s OUTPUT