Skip to content

Instantly share code, notes, and snippets.

@yuroyoro
Created March 11, 2015 06:10
Show Gist options
  • Select an option

  • Save yuroyoro/c9a65507396a4da4377a to your computer and use it in GitHub Desktop.

Select an option

Save yuroyoro/c9a65507396a4da4377a to your computer and use it in GitHub Desktop.

以下のissueをfixするPR. Major performance regression when preloading has_many_through association · Issue #12537 · rails/rails rails/rails#12537

commitはこれ https://github.com/yuroyoro/rails/commit/b348115f1d0cc8d3aa363568b6692ad312941a91


I profiled the benchmark code that preloads has_many_through association, and found that most of time spent by calling CollectionAssociation#reader method in associated_records_by_owner.

Here is a result of profiling associated_records_by_owner method.

CollectionAssociation#reader creates new CollectionProxy object if it doesn't exists. But, instantiate CollectionProxy is expensive operation. Because creating the Relation object by calling Association#scope is expensive, and merging it into CollectionProxy is also.

https://github.com/rails/rails/commit/c86a32d7451c5d901620ac58630460915292f88b#commitcomment-5384529

In this case, the association's records are already loaded by the preloader. It just read records by Association#target that returns loaded records, instead of reader method.

Here are benchmark results.

================================================================================
3.2.21 - postgresql
================================================================================

Calculating -------------------------------------
  limit 100 has_many    13.000  i/100ms
limit 100 has_many_through
                         5.000  i/100ms
limit 100 double has_many_through
                         3.000  i/100ms
 limit 1000 has_many     1.000  i/100ms
limit 1000 has_many_through
                         1.000  i/100ms
limit 1000 double has_many_through
                         1.000  i/100ms
-------------------------------------------------
  limit 100 has_many    133.936  (± 3.7%) i/s -    676.000
limit 100 has_many_through
                         55.424  (± 7.2%) i/s -    275.000
limit 100 double has_many_through
                         33.253  (± 6.0%) i/s -    168.000
 limit 1000 has_many     16.665  (± 6.0%) i/s -     84.000
limit 1000 has_many_through
                          6.633  (± 0.0%) i/s -     34.000
limit 1000 double has_many_through
                          3.664  (± 0.0%) i/s -     19.000

================================================================================
4.2.0 - postgresql
================================================================================

Calculating -------------------------------------
  limit 100 has_many    10.000  i/100ms
limit 100 has_many_through
                         1.000  i/100ms
limit 100 double has_many_through
                         1.000  i/100ms
 limit 1000 has_many     1.000  i/100ms
limit 1000 has_many_through
                         1.000  i/100ms
limit 1000 double has_many_through
                         1.000  i/100ms
-------------------------------------------------
  limit 100 has_many    106.059  (± 7.5%) i/s -    530.000
limit 100 has_many_through
                         15.979  (± 6.3%) i/s -     79.000
limit 100 double has_many_through
                          8.896  (±11.2%) i/s -     45.000
 limit 1000 has_many     13.351  (± 7.5%) i/s -     66.000
limit 1000 has_many_through
                          1.664  (± 0.0%) i/s -      9.000  in   5.438504s
limit 1000 double has_many_through
                          0.936  (± 0.0%) i/s -      5.000  in   5.352846s

================================================================================
4.2.1.rc3 (After)  - postgresql
================================================================================

Calculating -------------------------------------
  limit 100 has_many    10.000  i/100ms
limit 100 has_many_through
                         3.000  i/100ms
limit 100 double has_many_through
                         2.000  i/100ms
 limit 1000 has_many     1.000  i/100ms
limit 1000 has_many_through
                         1.000  i/100ms
limit 1000 double has_many_through
                         1.000  i/100ms
-------------------------------------------------
  limit 100 has_many    117.193  (± 6.8%) i/s -    590.000
limit 100 has_many_through
                         41.624  (± 7.2%) i/s -    207.000
limit 100 double has_many_through
                         25.446  (± 7.9%) i/s -    126.000
 limit 1000 has_many     14.516  (± 6.9%) i/s -     72.000
limit 1000 has_many_through
                          4.742  (± 0.0%) i/s -     24.000
limit 1000 double has_many_through
                          2.816  (± 0.0%) i/s -     14.000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment