Skip to content

Commit d49761c

Browse files
authored
Merge pull request rails#35847 from kamipo/optimizer_hints_with_count_subquery
Optimizer hints should be applied on Top level query as much as possible
2 parents eda2d7d + 7fb2ba5 commit d49761c

File tree

5 files changed

+30
-5
lines changed

5 files changed

+30
-5
lines changed

activerecord/lib/active_record/collection_cache_key.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ def collection_cache_key(collection = all, timestamp_column = :updated_at) # :no
2323
query = collection.select("#{column} AS collection_cache_key_timestamp")
2424
subquery_alias = "subquery_for_cache_key"
2525
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
26-
subquery = query.arel.as(subquery_alias)
27-
arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
26+
arel = query.send(:build_subquery, subquery_alias, select_values % subquery_column)
2827
else
2928
query = collection.unscope(:order)
3029
query.select_values = [select_values % column]

activerecord/lib/active_record/relation/calculations.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,16 +416,17 @@ def select_for_count
416416

417417
def build_count_subquery(relation, column_name, distinct)
418418
if column_name == :all
419+
column_alias = Arel.star
419420
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
420421
else
421422
column_alias = Arel.sql("count_column")
422423
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
423424
end
424425

425-
subquery = relation.arel.as(Arel.sql("subquery_for_count"))
426-
select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
426+
subquery_alias = Arel.sql("subquery_for_count")
427+
select_value = operation_over_aggregate_column(column_alias, "count", false)
427428

428-
Arel::SelectManager.new(subquery).project(select_value)
429+
relation.build_subquery(subquery_alias, select_value)
429430
end
430431
end
431432
end

activerecord/lib/active_record/relation/query_methods.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,15 @@ def arel(aliases = nil) # :nodoc:
992992
@arel ||= build_arel(aliases)
993993
end
994994

995+
protected
996+
def build_subquery(subquery_alias, select_value) # :nodoc:
997+
subquery = except(:optimizer_hints).arel.as(subquery_alias)
998+
999+
Arel::SelectManager.new(subquery).project(select_value).tap do |arel|
1000+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
1001+
end
1002+
end
1003+
9951004
private
9961005
# Returns a relation value with a given name
9971006
def get_value(name)

activerecord/test/cases/adapters/mysql2/optimizer_hints_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ def test_optimizer_hints
1515
end
1616
end
1717

18+
def test_optimizer_hints_with_count_subquery
19+
assert_sql(%r{\ASELECT /\*\+ NO_RANGE_OPTIMIZATION\(posts index_posts_on_author_id\) \*/}) do
20+
posts = Post.optimizer_hints("NO_RANGE_OPTIMIZATION(posts index_posts_on_author_id)")
21+
posts = posts.select(:id).where(author_id: [0, 1]).limit(5)
22+
assert_equal 5, posts.count
23+
end
24+
end
25+
1826
def test_optimizer_hints_is_sanitized
1927
assert_sql(%r{\ASELECT /\*\+ NO_RANGE_OPTIMIZATION\(posts index_posts_on_author_id\) \*/}) do
2028
posts = Post.optimizer_hints("/*+ NO_RANGE_OPTIMIZATION(posts index_posts_on_author_id) */")

activerecord/test/cases/adapters/postgresql/optimizer_hints_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ def test_optimizer_hints
1919
end
2020
end
2121

22+
def test_optimizer_hints_with_count_subquery
23+
assert_sql(%r{\ASELECT /\*\+ SeqScan\(posts\) \*/}) do
24+
posts = Post.optimizer_hints("SeqScan(posts)")
25+
posts = posts.select(:id).where(author_id: [0, 1]).limit(5)
26+
assert_equal 5, posts.count
27+
end
28+
end
29+
2230
def test_optimizer_hints_is_sanitized
2331
assert_sql(%r{\ASELECT /\*\+ SeqScan\(posts\) \*/}) do
2432
posts = Post.optimizer_hints("/*+ SeqScan(posts) */")

0 commit comments

Comments
 (0)