2019-05-02 18:17:27 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2015-05-13 02:45:59 -04:00
|
|
|
# Speeds up #pluck so its about 2.2x faster, importantly makes pluck avoid creation of a slew
|
|
|
|
# of AR objects
|
2016-12-27 03:08:54 -05:00
|
|
|
#
|
2018-06-07 06:38:22 -04:00
|
|
|
#
|
2015-05-13 02:45:59 -04:00
|
|
|
class ActiveRecord::Relation
|
|
|
|
|
2015-05-15 00:15:33 -04:00
|
|
|
# Note: In discourse, the following code is included in lib/sql_builder.rb
|
|
|
|
#
|
2015-05-13 02:45:59 -04:00
|
|
|
# class RailsDateTimeDecoder < PG::SimpleDecoder
|
|
|
|
# def decode(string, tuple=nil, field=nil)
|
|
|
|
# if Rails.version >= "4.2.0"
|
|
|
|
# @caster ||= ActiveRecord::Type::DateTime.new
|
|
|
|
# @caster.type_cast_from_database(string)
|
|
|
|
# else
|
|
|
|
# ActiveRecord::ConnectionAdapters::Column.string_to_time string
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class ActiveRecordTypeMap < PG::BasicTypeMapForResults
|
|
|
|
# def initialize(connection)
|
|
|
|
# super(connection)
|
|
|
|
# rm_coder 0, 1114
|
|
|
|
# add_coder RailsDateTimeDecoder.new(name: "timestamp", oid: 1114, format: 0)
|
|
|
|
# # we don't need deprecations
|
|
|
|
# self.default_type_map = PG::TypeMapInRuby.new
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# def self.pg_type_map
|
|
|
|
# conn = ActiveRecord::Base.connection.raw_connection
|
|
|
|
# @typemap ||= ActiveRecordTypeMap.new(conn)
|
|
|
|
# end
|
|
|
|
|
|
|
|
class ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
2016-12-27 03:08:54 -05:00
|
|
|
def select_raw(arel, name = nil, binds = [], &block)
|
2018-06-05 03:29:17 -04:00
|
|
|
arel = arel_from_relation(arel)
|
|
|
|
sql, binds = to_sql_and_binds(arel, binds)
|
2016-12-27 03:08:54 -05:00
|
|
|
execute_and_clear(sql, name, binds, &block)
|
2015-05-13 02:45:59 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-06-05 03:29:17 -04:00
|
|
|
def pluck(*column_names)
|
|
|
|
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
|
|
|
return records.pluck(*column_names)
|
2015-05-13 02:45:59 -04:00
|
|
|
end
|
|
|
|
|
2018-06-05 03:29:17 -04:00
|
|
|
if has_include?(column_names.first)
|
|
|
|
relation = apply_join_dependency
|
|
|
|
relation.pluck(*column_names)
|
2015-05-13 02:45:59 -04:00
|
|
|
else
|
2018-06-05 03:29:17 -04:00
|
|
|
enforce_raw_sql_whitelist(column_names)
|
2015-05-13 02:45:59 -04:00
|
|
|
relation = spawn
|
|
|
|
|
2018-06-05 03:29:17 -04:00
|
|
|
relation.select_values = column_names.map { |cn|
|
|
|
|
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
2015-05-13 02:45:59 -04:00
|
|
|
}
|
|
|
|
|
2018-06-05 03:29:17 -04:00
|
|
|
klass.connection.select_raw(relation.arel) do |result, _|
|
2018-06-20 03:50:31 -04:00
|
|
|
result.type_map = DB.type_map
|
2015-05-13 02:45:59 -04:00
|
|
|
result.nfields == 1 ? result.column_values(0) : result.values
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# require 'benchmark/ips'
|
|
|
|
#
|
|
|
|
# ENV['RAILS_ENV'] = 'production'
|
|
|
|
# require File.expand_path("../../config/environment", __FILE__)
|
|
|
|
#
|
|
|
|
# Benchmark.ips do |x|
|
|
|
|
# x.report("fast_pluck") do
|
|
|
|
# Post.where(topic_id: 48464).fast_pluck(:id)
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# x.report("pluck") do
|
|
|
|
# Post.where(topic_id: 48464).pluck(:id)
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# % ruby tmp/fast_pluck.rb
|
|
|
|
# Calculating -------------------------------------
|
|
|
|
# fast_pluck 165.000 i/100ms
|
|
|
|
# pluck 80.000 i/100ms
|
|
|
|
# -------------------------------------------------
|
|
|
|
# fast_pluck 1.720k (± 8.8%) i/s - 8.580k
|
|
|
|
# pluck 807.913 (± 4.0%) i/s - 4.080k
|
|
|
|
#
|