FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Eager-load host and chapter-organiser chains for event listings by mroderick · Pull Request #2909 · codebar/planner · GitHub

Eager-load host and chapter-organiser chains for event listings - #2909

Open
mroderick wants to merge 1 commit into
masterfrom
performance/events-upcoming-queries
Open

mroderick wants to merge 1 commit into
masterfrom
performance/events-upcoming-queries

Conversation

Copy link
Copy Markdown
Collaborator

Summary

GET /events/upcoming rendered ~31 queries per request (production median 467ms). Three per-card query sources, all association hops the existing eager loads didn't cover:

  1. WorkshopPresenter#venue → model.host → workshop_host.sponsor — the sponsor behind the has_one :host through-chain loaded one query per hosted workshop (13 on the measured page)
  2. WorkshopPresenter#organisers falls back to the chapter's organiser members when a workshop has none; chapter.permissions.find_by(name: 'organiser') loaded one query per such card
  3. latest_model_updated ran its four MAX queries twice — fresh_when received it as both the Last-Modified value and the etag

Changes

  • The workshop eager load now covers workshop_host: :sponsor and chapter: { permissions: :members }
  • chapter_organisers reads the loaded collections instead of find_by, which builds a new relation and bypasses the association cache
  • latest_model_updated is computed once in upcoming and past
Measured

Against codebar_production_dump (fragment cache warm): 26 queries → 9, warm render ~115ms either way. Reproduced the production shape: the 13 single-sponsor queries and the double MAX queries are gone.

Review notes

  • Riskiest part: the workshop query now joins chapters → permissions → members. Only members attached to a chapter's organiser permission join in, so row multiplication is bounded, but worth a look.
  • chapter_organisers behaviour is unchanged for empty results (nil → [] in both shapes).
  • ETag/Last-Modified values are identical, just computed once — cheapest to review.
  • Deliberately not done: the chapter page has its own non-eager load path and still N+1s per fallback card (pre-existing); /events/past shares load_events but has no query-count guard of its own.

Verify

Query count drops in production (Scout APM: /events/upcoming); median duration drops with it; ETag behaviour unchanged.

Fixes #2888

/events/upcoming issued ~31 queries per render (production median 467ms).
Three per-card query sources, all association hops the existing eager
loads didn't cover:

- WorkshopPresenter#venue -> model.host -> workshop_host.sponsor: the
  belongs_to sponsor behind the has_one :host through-chain now loads
  with the workshop (13 single-sponsor queries on the production page).
- WorkshopPresenter#organisers falls back to the chapter's organiser
  permission members; that hop now loads with the chapter, and
  chapter_organisers reads the loaded collections instead of find_by
  (which would bypass the association cache).
- latest_model_updated ran its 4 MAX queries twice (once for fresh_when's
  Last-Modified, once for the etag); compute it once.

Against codebar_production_dump: 26 queries -> 9, warm render ~115ms.

Fixes #2888
mroderick marked this pull request as ready for review September 19, 2026 13:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.

/events/upcoming: 31 queries and ~467ms median per render

2 participants


Back | FazBrowse Home | New Git URL