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 Sep 28, 2023
1 parent 90b0266 commit c4cb732
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(")

This comment has been minimized.

Copy link
@andyatkinson

andyatkinson Oct 11, 2023

Extremely minor but you want want to capitalize ANY and ALL as keywords.

I'm not familiar with Arel much, but I'm wondering if "to_sql" on a AR relation that includes an IN clause, and now has any ANY clause, would break? I left this comment here: rails#49388 (comment) where I'm wondering if that's what that code does. At a quick glance it seems like the to_sql code has not changed between 6.1 and main.

Thanks!


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 c4cb732

Please sign in to comment.