diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index e2c188d3bc4df..e797418dbfd3d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -838,7 +838,14 @@ def self.strict_loading_value def preload_associations(records) # :nodoc: preload = preload_values - preload += eager_loading? ? includes_values_non_referenced : includes_values + if ENV["SLIM_PATCH"].present? + preload += eager_loading? ? includes_values_non_referenced : includes_values + elsif ENV["SLIM_PATCH_CODE_ONLY"].present? + includes_values_non_referenced + preload += includes_values unless eager_loading? + else + preload += includes_values unless eager_loading? + end scope = strict_loading_value ? StrictLoadingScope : nil preload.each do |associations| ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 870342e6f755a..7851e176dc086 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -408,10 +408,21 @@ def construct_relation_for_exists(conditions) end def apply_join_dependency(eager_loading: group_values.empty?, full_eager_loading: false) - selected_includes_values = full_eager_loading ? includes_values : includes_values_referenced - join_dependency = construct_join_dependency( - eager_load_values | selected_includes_values, Arel::Nodes::OuterJoin - ) + if ENV["SLIM_PATCH"].present? + selected_includes_values = full_eager_loading ? includes_values : includes_values_referenced + join_dependency = construct_join_dependency( + eager_load_values | selected_includes_values, Arel::Nodes::OuterJoin + ) + elsif ENV["SLIM_PATCH_CODE_ONLY"].present? + selected_includes_values = full_eager_loading ? includes_values : includes_values_referenced + join_dependency = construct_join_dependency( + eager_load_values | includes_values, Arel::Nodes::OuterJoin + ) + else + join_dependency = construct_join_dependency( + eager_load_values | includes_values, Arel::Nodes::OuterJoin + ) + end relation = except(:includes, :eager_load, :preload).joins!(join_dependency) if eager_loading && has_limit_or_offset? && !( diff --git a/activerecord/test/cases/associations/performance_test.rb b/activerecord/test/cases/associations/performance_test.rb new file mode 100644 index 0000000000000..2b71effba583b --- /dev/null +++ b/activerecord/test/cases/associations/performance_test.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require "cases/helper" +require "cases/encryption/helper" +require "models/author" +require "models/book" +require "models/citation" +require "models/reader" +require "models/post" +require "models/reference" +require "models/comment" +require "models/rating" +require "models/category" +require "models/categorization" +require "models/tag" +require "models/tagging" +require "models/person" +require "models/club" +require "models/developer" +require "models/project" +require "models/computer" +require "models/company" +require "models/contract" +require "models/member" +require "models/membership" +require "models/sponsor" + +class AssociationsPerformanceTest < ActiveRecord::TestCase + include ActiveRecord::Encryption::PerformanceHelpers + + fixtures :authors, :books, :citations, :readers, :posts, :references, :comments, :ratings, + :categories, :categorizations, :tags, :taggings, :people, :clubs, :members, :memberships, + :sponsors, :developers, :projects, :developers_projects, :computers, :companies, :accounts + + DURATION = 10 + + def test_performance_tree_code_only + baseline = lambda do + ENV["SLIM_PATCH_CODE_ONLY"] = nil + ENV["SLIM_PATCH"] = nil + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_a + end + + assert_slower_by_at_most 1.05, baseline: baseline, duration: DURATION do + ENV["SLIM_PATCH_CODE_ONLY"] = "true" + ENV["SLIM_PATCH"] = nil + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_a + end + end + + def test_performance_objects_allocating + baseline = lambda do + ENV["SLIM_PATCH_CODE_ONLY"] = nil + ENV["SLIM_PATCH"] = nil + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_a + end + + assert_slower_by_at_most 1.2, baseline: baseline, duration: DURATION do + ENV["SLIM_PATCH_CODE_ONLY"] = nil + ENV["SLIM_PATCH"] = "true" + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_a + end + end + + def test_performance_sql_only + baseline = lambda do + ENV["SLIM_PATCH_CODE_ONLY"] = nil + ENV["SLIM_PATCH"] = nil + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_sql + end + + assert_slower_by_at_most 0.7, baseline: baseline, duration: DURATION do + ENV["SLIM_PATCH_CODE_ONLY"] = nil + ENV["SLIM_PATCH"] = "true" + authors = Author.includes( + :books, { posts: :special_comments }, { categorizations: :category } + ).order("comments.body").where("posts.id = 4") + authors.to_sql + end + end +end