aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2018-01-11 02:19:58 +0900
committerRyuta Kamizono <kamipo@gmail.com>2018-01-11 03:29:50 +0900
commitb4f64cb1595f2abd3d7e47805273f4f029718829 (patch)
tree3e58dbd5911596ce663a0e2f30ce3ae6c0b01fca /activerecord
parent96f59306101a6ee252df2a9636ef2569d26924f7 (diff)
downloadrails-b4f64cb1595f2abd3d7e47805273f4f029718829.tar.gz
rails-b4f64cb1595f2abd3d7e47805273f4f029718829.tar.bz2
rails-b4f64cb1595f2abd3d7e47805273f4f029718829.zip
Make `relation.exists?` more performant when using eager loading
`relation.exists?` just wants to know if there is a result or not, does not need the exact records matched. Therefore, an intermediate SELECT query for eager loading is not necessary.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb7
-rw-r--r--activerecord/test/cases/finder_test.rb22
2 files changed, 16 insertions, 13 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 50d0f14b98..12ac89f5ad 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -313,7 +313,7 @@ module ActiveRecord
return false if !conditions || limit_value == 0
if eager_loading?
- relation = apply_join_dependency(construct_join_dependency(eager_loading: false))
+ relation = apply_join_dependency(eager_loading: false)
return relation.exists?(conditions)
end
@@ -396,10 +396,11 @@ module ActiveRecord
)
end
- def apply_join_dependency(join_dependency = construct_join_dependency)
+ def apply_join_dependency(join_dependency = nil, eager_loading: true)
+ join_dependency ||= construct_join_dependency(eager_loading: eager_loading)
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
- if using_limitable_reflections?(join_dependency.reflections)
+ if !eager_loading || using_limitable_reflections?(join_dependency.reflections)
relation
else
if has_limit_or_offset?
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 95bd987551..4769ffd64d 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -270,25 +270,27 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists_with_includes_limit_and_empty_result
- assert_equal false, Topic.includes(:replies).limit(0).exists?
- assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists?
+ assert_no_queries { assert_equal false, Topic.includes(:replies).limit(0).exists? }
+ assert_queries(1) { assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists? }
end
def test_exists_with_distinct_association_includes_and_limit
author = Author.first
- assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
- assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
+ unique_categorized_posts = author.unique_categorized_posts.includes(:special_comments)
+ assert_no_queries { assert_equal false, unique_categorized_posts.limit(0).exists? }
+ assert_queries(1) { assert_equal true, unique_categorized_posts.limit(1).exists? }
end
def test_exists_with_distinct_association_includes_limit_and_order
author = Author.first
- assert_equal false, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(0).exists?
- assert_equal true, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(1).exists?
+ unique_categorized_posts = author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC")
+ assert_no_queries { assert_equal false, unique_categorized_posts.limit(0).exists? }
+ assert_queries(1) { assert_equal true, unique_categorized_posts.limit(1).exists? }
end
def test_exists_should_reference_correct_aliases_while_joining_tables_of_has_many_through_association
- developer = developers(:david)
- assert_not_predicate developer.ratings.includes(comment: :post).where(posts: { id: 1 }), :exists?
+ ratings = developers(:david).ratings.includes(comment: :post).where(posts: { id: 1 })
+ assert_queries(1) { assert_not_predicate ratings.limit(1), :exists? }
end
def test_exists_with_empty_table_and_no_args_given
@@ -1315,12 +1317,12 @@ class FinderTest < ActiveRecord::TestCase
test "#skip_query_cache! for #exists? with a limited eager load" do
Topic.cache do
- assert_queries(2) do
+ assert_queries(1) do
Topic.eager_load(:replies).limit(1).exists?
Topic.eager_load(:replies).limit(1).exists?
end
- assert_queries(4) do
+ assert_queries(2) do
Topic.eager_load(:replies).limit(1).skip_query_cache!.exists?
Topic.eager_load(:replies).limit(1).skip_query_cache!.exists?
end