Skip to content

Fix N+1 query on signup bucket/requested_bucket in UserConProfileDrop - #11882

Merged
nbudin merged 1 commit into
mainfrom
fix-user-signups-bucket-n-plus-one
Aug 6, 2026
Merged

Fix N+1 query on signup bucket/requested_bucket in UserConProfileDrop#11882
nbudin merged 1 commit into
mainfrom
fix-user-signups-bucket-n-plus-one

Conversation

@nbudin

@nbudin nbudin commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

After #11880 deployed, Sentry surfaced a new batch of N+1 issues (INTERCODE-186, 187, 189) with the offending query SELECT registration_policy_buckets.* WHERE id = $1 LIMIT $2, under AppRootLayoutQuery/CmsPageQuery. This is a genuinely different N+1 than the one #11880 fixed -- that one was a has_many collection load (registration_policy_buckets WHERE registration_policy_id = X); this one is belongs_to lookups (bucket/requested_bucket by their own id), so #11880's preload didn't cover it. It's likely this N+1 already existed since #11871 but was masked in Sentry's grouping by the much larger N+1 #11880 just fixed -- once that one went quiet, this one became the dominant signal.

Root cause

Traced it (by grepping actual CMS partial content in a production data dump) to a default/stock CMS partial pair present on most conventions' sites -- user_signups/user_signup (the "My Schedule" widget) and signup_bucket_description, which it renders per signup:

{%- elsif signup.bucket.name -%}
  ...
  {%- if signup.requested_bucket -%}

UserConProfileDrop#signups backs user_con_profile.signups for this widget. It already preloads several associations (event, run, rooms, team_members) but never picked up :bucket/:requested_bucket -- these only became real belongs_to associations in #11871 (previously bucket_key/requested_bucket_key were plain string columns needing no extra query at all), so the widget's preload list was never updated for them.

Fix

Added :bucket, :requested_bucket to UserConProfileDrop#signups's .includes(...). Added a regression test verified to fail without the fix (10 queries for 5 signups) and pass with it (2 total -- one batched query each for bucket and requested_bucket).

Also fixed a pre-existing (unrelated) Lint/MissingSuper rubocop offense on this same file's initialize, since the pre-commit hook rejects it once the file is touched at all.

Test plan

  • test/liquid_drops/user_con_profile_drop_test.rb (new N+1 regression test + full existing suite)
  • Full test/liquid_drops/ suite (39 tests)
  • rubocop / stree clean

🤖 Generated with Claude Code

…#signups

Sentry showed a new registration_policy_buckets-by-id N+1
(INTERCODE-186/187/189) after #11880 shipped -- it had been masked by
the much larger registration_policy/buckets N+1 that #11880 fixed,
and became the dominant N+1 once that one was gone.

Traced it to the "My Schedule" widget (the user_signups/signup_bucket_description
CMS partials, present by default on most conventions' sites), which calls
signup.bucket.name / signup.requested_bucket.name per signup.
UserConProfileDrop#signups already preloads several associations but
never picked up :bucket/:requested_bucket -- these only became real
belongs_to associations in #11871 (they used to be plain string
columns needing no extra query at all), so this gap predates #11880
but was previously hidden under the louder N+1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@nbudin
nbudin merged commit ac68f4e into main Aug 6, 2026
14 of 39 checks passed
@nbudin
nbudin deleted the fix-user-signups-bucket-n-plus-one branch August 6, 2026 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant