Skip to content

Instantly share code, notes, and snippets.

@dvandersluis
Last active November 23, 2018 16:51
Show Gist options
  • Select an option

  • Save dvandersluis/c5962d3f7074932d39533c47c4f8b52f to your computer and use it in GitHub Desktop.

Select an option

Save dvandersluis/c5962d3f7074932d39533c47c4f8b52f to your computer and use it in GitHub Desktop.

Revisions

  1. dvandersluis revised this gist Nov 23, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions 1 - benchmark.rb
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,7 @@ module ActiveRecord
    module Calculations
    alias_method :old_pluck, :pluck

    # original: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/calculations.rb#L184-L201
    def pluck(*column_names)
    if loaded?
    # If only one column is given, and it's an attribute, just call the attribute method
  2. dvandersluis created this gist Nov 23, 2018.
    41 changes: 41 additions & 0 deletions 1 - benchmark.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    require 'benchmark/ips'

    collection = User.limit(1)

    module ActiveRecord
    module Calculations
    alias_method :old_pluck, :pluck

    def pluck(*column_names)
    if loaded?
    # If only one column is given, and it's an attribute, just call the attribute method
    if column_names.length == 1 && @klass.has_attribute?(column_names.first)
    return records.map{ |r| r._read_attribute(column_names.first) }
    elsif (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
    # otherwise fallback to previous behaviour
    return records.pluck(*column_names)
    end
    end

    if has_include?(column_names.first)
    relation = apply_join_dependency
    relation.pluck(*column_names)
    else
    enforce_raw_sql_whitelist(column_names)
    relation = spawn
    relation.select_values = column_names.map { |cn|
    @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
    }
    result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
    result.cast_values(klass.attribute_types)
    end
    end
    end
    end

    Benchmark.ips do |x|
    x.report('map') { collection.map(&:first_name) }
    x.report('old_pluck') { collection.old_pluck(:first_name) }
    x.report('pluck') { collection.pluck(:first_name) }
    x.compare!
    end
    13 changes: 13 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    Warming up --------------------------------------
    map 56.596k i/100ms
    old_pluck 11.714k i/100ms
    pluck 65.071k i/100ms
    Calculating -------------------------------------
    map 752.586k (± 4.9%) i/s - 3.792M in 5.051037s
    old_pluck 121.499k (± 3.8%) i/s - 609.128k in 5.020716s
    pluck 781.728k (± 5.8%) i/s - 3.904M in 5.013820s

    Comparison:
    pluck: 781728.0 i/s
    map: 752586.3 i/s - same-ish: difference falls within error
    old_pluck: 121499.3 i/s - 6.43x slower