Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ActiveRecord: Improve find_db_config performance
I noticed an application spending ~5ms on `find_db_config`, with a lot of time spent on sorting the database configs and comparing the arrays (`Array#<=>`). I updated `find_db_config` to avoid the sort entirely. Here is a benchmark script I used to measure the improvement: ``` require "bundler/inline" gemfile(true) do source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem "rails", github: "rails/rails", branch: "main" gem "benchmark-ips" end require "active_record" require "active_record/database_configurations" module ActiveRecord class DatabaseConfigurations def fast_find_db_config(env) current_env_configs, other_configs = configurations.partition(&:for_current_env?) [*current_env_configs, *other_configs].find do |db_config| db_config.env_name == env.to_s || (db_config.for_current_env? && db_config.name == env.to_s) end end end end def generate_configs(adapter, count) count.times.to_h do |i| [i == 0 ? "primary" : "config_#{i}", { "adapter" => adapter }] end end small_config = ActiveRecord::DatabaseConfigurations.new( **generate_configs("sqlite3", 3) ) large_config = ActiveRecord::DatabaseConfigurations.new({ **generate_configs("randomadapter", 100), ActiveRecord::ConnectionHandling::DEFAULT_ENV.call => generate_configs("sqlite3", 100) }) SCENARIOS = { "Empty" => ActiveRecord::DatabaseConfigurations.new({}), "A few connections" => small_config, "Hundreds of connections" => large_config, } SCENARIOS.each_pair do |name, value| puts puts " #{name} ".center(80, "=") puts Benchmark.ips do |x| x.report("find_db_config") { value.find_db_config("primary") } x.report("fast_find_db_config") { value.fast_find_db_config("primary") } x.compare! end end ``` The results show a consistent speedup, especially for many configs: ==================================== Empty ===================================== Warming up -------------------------------------- find_db_config 82.849k i/100ms fast_find_db_config 172.141k i/100ms Calculating ------------------------------------- find_db_config 830.202k (± 1.9%) i/s - 4.225M in 5.091388s fast_find_db_config 1.633M (± 6.6%) i/s - 8.263M in 5.082794s Comparison: fast_find_db_config: 1633426.8 i/s find_db_config: 830201.9 i/s - 1.97x slower ============================== A few connections =============================== Warming up -------------------------------------- find_db_config 25.356k i/100ms fast_find_db_config 47.260k i/100ms Calculating ------------------------------------- find_db_config 248.648k (± 2.7%) i/s - 1.268M in 5.102833s fast_find_db_config 475.184k (± 3.0%) i/s - 2.410M in 5.077268s Comparison: fast_find_db_config: 475184.1 i/s find_db_config: 248647.6 i/s - 1.91x slower =========================== Hundreds of connections ============================ Warming up -------------------------------------- find_db_config 361.000 i/100ms fast_find_db_config 2.400k i/100ms Calculating ------------------------------------- find_db_config 3.622k (± 1.9%) i/s - 18.411k in 5.085694s fast_find_db_config 24.073k (± 2.0%) i/s - 122.400k in 5.086726s Comparison: fast_find_db_config: 24073.0 i/s find_db_config: 3621.5 i/s - 6.65x slower
- Loading branch information