Skip to content

Instantly share code, notes, and snippets.

@dvandersluis
Last active November 23, 2018 16:51
Show Gist options
  • Save dvandersluis/c5962d3f7074932d39533c47c4f8b52f to your computer and use it in GitHub Desktop.
Save dvandersluis/c5962d3f7074932d39533c47c4f8b52f to your computer and use it in GitHub Desktop.
Fixing ActiveRecord_Relation#pluck vs map
require 'benchmark/ips'
collection = User.limit(1)
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
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
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment