mirror of https://github.com/rails/rails
Avoid query from calculations on contradictory relation
Previously calculations would make a query even when passed a contradiction, like `User.where(id: []).count`. This commit optimzes that to avoid an unnecessary query to the database. Co-authored-by: John Hawthorn <jhawthorn@github.com> Co-authored-by: Daniel Colson <composerinteralia@github.com>
This commit is contained in:
parent
4b5410a6aa
commit
a1f76dd712
|
@ -1,3 +1,14 @@
|
|||
* Avoid queries when performing calculations on contradictory relations.
|
||||
|
||||
Previously calculations would make a query even when passed a
|
||||
contradiction, such as `User.where(id: []).count`. We no longer perform a
|
||||
query in that scenario.
|
||||
|
||||
This applies to the following calculations: `count`, `sum`, `average`,
|
||||
`minimum` and `maximum`
|
||||
|
||||
*Luan Vieira, John Hawthorn and Daniel Colson*
|
||||
|
||||
* Allow using aliased attributes with `insert_all`/`upsert_all`.
|
||||
|
||||
```ruby
|
||||
|
|
|
@ -342,6 +342,7 @@ module ActiveRecord
|
|||
# Shortcut when limit is zero.
|
||||
return 0 if limit_value == 0
|
||||
|
||||
relation = self
|
||||
query_builder = build_count_subquery(spawn, column_name, distinct)
|
||||
else
|
||||
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
||||
|
@ -356,8 +357,12 @@ module ActiveRecord
|
|||
query_builder = relation.arel
|
||||
end
|
||||
|
||||
query_result = skip_query_cache_if_necessary do
|
||||
@klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}", async: @async)
|
||||
query_result = if relation.where_clause.contradiction?
|
||||
ActiveRecord::Result.empty
|
||||
else
|
||||
skip_query_cache_if_necessary do
|
||||
@klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}", async: @async)
|
||||
end
|
||||
end
|
||||
|
||||
query_result.then do |result|
|
||||
|
|
|
@ -717,6 +717,36 @@ class CalculationsTest < ActiveRecord::TestCase
|
|||
Account.where("credit_limit > 50").from("accounts").maximum(:credit_limit)
|
||||
end
|
||||
|
||||
def test_no_queries_for_empty_relation_on_count
|
||||
assert_queries(0) do
|
||||
assert_equal 0, Post.where(id: []).count
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_queries_for_empty_relation_on_sum
|
||||
assert_queries(0) do
|
||||
assert_equal 0, Post.where(id: []).sum(:tags_count)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_queries_for_empty_relation_on_average
|
||||
assert_queries(0) do
|
||||
assert_nil Post.where(id: []).average(:tags_count)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_queries_for_empty_relation_on_minimum
|
||||
assert_queries(0) do
|
||||
assert_nil Account.where(id: []).minimum(:id)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_queries_for_empty_relation_on_maximum
|
||||
assert_queries(0) do
|
||||
assert_nil Account.where(id: []).maximum(:id)
|
||||
end
|
||||
end
|
||||
|
||||
def test_maximum_with_not_auto_table_name_prefix_if_column_included
|
||||
Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)])
|
||||
|
||||
|
|
Loading…
Reference in New Issue