mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #39022 from kamipo/perf_where_in
PERF: Improve performance of where when using an array of values
This commit is contained in:
commit
9817d74f3b
7 changed files with 34 additions and 38 deletions
|
@ -20,20 +20,17 @@ module ActiveRecord
|
|||
case values.length
|
||||
when 0 then NullPredicate
|
||||
when 1 then predicate_builder.build(attribute, values.first)
|
||||
else
|
||||
values.map! do |v|
|
||||
predicate_builder.build_bind_attribute(attribute.name, v)
|
||||
end
|
||||
values.empty? ? NullPredicate : attribute.in(values)
|
||||
else attribute.in(values)
|
||||
end
|
||||
|
||||
unless nils.empty?
|
||||
if nils.empty?
|
||||
return values_predicate if ranges.empty?
|
||||
else
|
||||
values_predicate = values_predicate.or(predicate_builder.build(attribute, nil))
|
||||
end
|
||||
|
||||
array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
|
||||
array_predicates.unshift(values_predicate)
|
||||
array_predicates.inject(&:or)
|
||||
array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) }
|
||||
array_predicates.inject(values_predicate, &:or)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -91,7 +91,7 @@ module ActiveRecord
|
|||
predicates.any? do |x|
|
||||
case x
|
||||
when Arel::Nodes::In
|
||||
Array === x.right && x.right.empty?
|
||||
Arel::Nodes::CastedArray === x.right && x.right.value.empty?
|
||||
when Arel::Nodes::Equality
|
||||
x.right.respond_to?(:unboundable?) && x.right.unboundable?
|
||||
end
|
||||
|
|
|
@ -34,6 +34,16 @@ module Arel # :nodoc: all
|
|||
alias :== :eql?
|
||||
end
|
||||
|
||||
class CastedArray < Casted # :nodoc:
|
||||
def value_for_database
|
||||
if attribute.able_to_type_cast?
|
||||
value.map { |v| attribute.type_cast_for_database(v) }
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Quoted < Arel::Nodes::Unary # :nodoc:
|
||||
alias :value_for_database :value
|
||||
alias :value_before_type_cast :value
|
||||
|
|
|
@ -31,7 +31,7 @@ module Arel # :nodoc: all
|
|||
end
|
||||
|
||||
def eq_all(others)
|
||||
grouping_all :eq, quoted_array(others)
|
||||
grouping_all :eq, others
|
||||
end
|
||||
|
||||
def between(other)
|
||||
|
@ -238,7 +238,7 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
|
|||
end
|
||||
|
||||
def quoted_array(others)
|
||||
others.map { |v| quoted_node(v) }
|
||||
Nodes::CastedArray.new(others, self)
|
||||
end
|
||||
|
||||
def infinity?(value)
|
||||
|
|
|
@ -98,6 +98,7 @@ module Arel # :nodoc: all
|
|||
|
||||
def type_cast_for_database(attribute_name, value)
|
||||
type_caster.type_cast_for_database(attribute_name, value)
|
||||
rescue ::RangeError
|
||||
end
|
||||
|
||||
def able_to_type_cast?
|
||||
|
|
|
@ -81,6 +81,10 @@ module Arel # :nodoc: all
|
|||
end
|
||||
end
|
||||
|
||||
def visit_Arel_Nodes_CastedArray(o, collector)
|
||||
collector << o.value_for_database.map! { |v| quote(v) }.join(", ")
|
||||
end
|
||||
|
||||
def visit_Arel_Nodes_Casted(o, collector)
|
||||
collector << quote(o.value_for_database).to_s
|
||||
end
|
||||
|
@ -513,12 +517,8 @@ module Arel # :nodoc: all
|
|||
collector.preparable = false
|
||||
attr, values = o.left, o.right
|
||||
|
||||
if Array === values
|
||||
unless values.empty?
|
||||
values.delete_if { |value| unboundable?(value) }
|
||||
end
|
||||
|
||||
return collector << "1=0" if values.empty?
|
||||
if Arel::Nodes::CastedArray === values
|
||||
return collector << "1=0" if values.value.empty?
|
||||
end
|
||||
|
||||
visit(attr, collector) << " IN ("
|
||||
|
@ -529,12 +529,8 @@ module Arel # :nodoc: all
|
|||
collector.preparable = false
|
||||
attr, values = o.left, o.right
|
||||
|
||||
if Array === values
|
||||
unless values.empty?
|
||||
values.delete_if { |value| unboundable?(value) }
|
||||
end
|
||||
|
||||
return collector << "1=1" if values.empty?
|
||||
if Arel::Nodes::CastedArray === values
|
||||
return collector << "1=1" if values.value.empty?
|
||||
end
|
||||
|
||||
visit(attr, collector) << " NOT IN ("
|
||||
|
|
|
@ -618,14 +618,14 @@ module Arel
|
|||
attribute = Attribute.new nil, nil
|
||||
node = attribute.between(-::Float::INFINITY..::Float::INFINITY)
|
||||
|
||||
_(node).must_equal Nodes::NotIn.new(attribute, [])
|
||||
_(node).must_equal attribute.not_in([])
|
||||
end
|
||||
|
||||
it "can be constructed with a quoted infinite range" do
|
||||
attribute = Attribute.new nil, nil
|
||||
node = attribute.between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false))
|
||||
|
||||
_(node).must_equal Nodes::NotIn.new(attribute, [])
|
||||
_(node).must_equal attribute.not_in([])
|
||||
end
|
||||
|
||||
it "can be constructed with a range ending at Infinity" do
|
||||
|
@ -707,11 +707,7 @@ module Arel
|
|||
|
||||
_(node).must_equal Nodes::In.new(
|
||||
attribute,
|
||||
[
|
||||
Nodes::Casted.new(1, attribute),
|
||||
Nodes::Casted.new(2, attribute),
|
||||
Nodes::Casted.new(3, attribute),
|
||||
]
|
||||
Nodes::CastedArray.new([1, 2, 3], attribute)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -831,14 +827,14 @@ module Arel
|
|||
attribute = Attribute.new nil, nil
|
||||
node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY)
|
||||
|
||||
_(node).must_equal Nodes::In.new(attribute, [])
|
||||
_(node).must_equal attribute.in([])
|
||||
end
|
||||
|
||||
it "can be constructed with a quoted infinite range" do
|
||||
attribute = Attribute.new nil, nil
|
||||
node = attribute.not_between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false))
|
||||
|
||||
_(node).must_equal Nodes::In.new(attribute, [])
|
||||
_(node).must_equal attribute.in([])
|
||||
end
|
||||
|
||||
it "can be constructed with a range ending at Infinity" do
|
||||
|
@ -934,11 +930,7 @@ module Arel
|
|||
|
||||
_(node).must_equal Nodes::NotIn.new(
|
||||
attribute,
|
||||
[
|
||||
Nodes::Casted.new(1, attribute),
|
||||
Nodes::Casted.new(2, attribute),
|
||||
Nodes::Casted.new(3, attribute),
|
||||
]
|
||||
Nodes::CastedArray.new([1, 2, 3], attribute)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue