Skip to content

Commit

Permalink
Reduce pg_stat_statements churn using = any() instead of IN ()
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlinsley committed Jun 5, 2024
1 parent e39361a commit ef446ce
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ module OID # :nodoc:
class Array < Type::Value # :nodoc:
include ActiveModel::Type::Helpers::Mutable

Data = Struct.new(:encoder, :values) # :nodoc:
Data = Struct.new(:encoder, :values) do # :nodoc:
def hash
[encoder.name, encoder.delimiter, values].hash
end
end

attr_reader :subtype, :delimiter
delegate :type, :user_input_in_time_zone, :limit, :precision, :scale, to: :subtype
Expand Down
20 changes: 20 additions & 0 deletions activerecord/lib/arel/visitors/postgresql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ def visit_Arel_Nodes_NullsLast(o, collector)
collector << " NULLS LAST"
end

# Postgres-specific implementation that uses `col = any('{1,2}')` instead of `col IN (1,2)`
# to avoid pg_stat_statements churn
def visit_Arel_Nodes_HomogeneousIn(o, collector)
oid = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
case o.attribute.type_caster
when oid::Bytea, oid::Jsonb
return super
end

visit o.left, collector
collector << (o.type == :in ? " = any(" : " != all(")

type_caster = oid::Array.new(o.attribute.type_caster, ",")
values = [type_caster.serialize(o.casted_values)]
proc_for_binds = -> value { ActiveModel::Attribute.with_cast_value(o.attribute.name, value, type_caster) }
collector.add_binds(values, proc_for_binds, &bind_block)

collector << ")"
end

BIND_BLOCK = proc { |i| "$#{i}" }
private_constant :BIND_BLOCK

Expand Down

0 comments on commit ef446ce

Please sign in to comment.