Performance regression in CollectionAssocation#build by ghiculescu · Pull Reques...
source link: https://github.com/rails/rails/pull/42524
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
#40379 caused a big regression in one of our apps when upgrading to Rails 6.1. If you have an association with lots of records and you call build
on it, the build
method takes a long time because it has to iterate over every object on the target
to check for duplicates.
This is necessary because of how has_many_inversing
works, but could be implemented to run more quickly. I've attempted to do that in this PR, by keeping a separate cache of records that were added to the target through has_many_inversing
and only searching for the matching record in that case.
Replication script for the bug, this fails against Rails 6.1 and main
, passes against Rails 6, passes when run against this branch:
# frozen_string_literal: true require "bundler/inline" gemfile(true) do source "https://rubygems.org" gem "rails", "~> 6.1.0" gem "sqlite3" end require "active_record" require "minitest/autorun" require "logger" # This connection will do for database-independent bug reports. ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Base.logger = Logger.new(STDOUT) ActiveRecord::Schema.define do create_table :authors, force: true do |t| end create_table :posts, force: true do |t| t.references :author end end class Author < ActiveRecord::Base has_many :posts end class Post < ActiveRecord::Base belongs_to :author end class BugTest < Minitest::Test def test_association_stuff author = Author.create! posts = 100_000.times.map { |n| { author_id: author.id } } Post.insert_all(posts) author = Author.find(author.id) author.posts.load_target 5000.times do |n| time = Benchmark.ms { author.posts.build } assert time < 30, "iteration #{n}: #{time}" # takes about 200ms in Rails 6.1 end end end
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK