Enhancement: Performance optimization for Kingdom, Park, and Attendance page loads#458
Open
baltinerdist wants to merge 1 commit into
Open
Enhancement: Performance optimization for Kingdom, Park, and Attendance page loads#458baltinerdist wants to merge 1 commit into
baltinerdist wants to merge 1 commit into
Conversation
…ce page loads ## Database indexes (db-migrations/2026-04-11-performance-indexes.sql) - Add 9 composite indexes on ork_attendance, ork_park, ork_mundane, ork_event_calendardetail, and ork_event_rsvp targeting the heaviest query patterns (26/52-week kingdom scans, park roster lookups, weekly/monthly GROUP BY on computed columns, RSVP counts) - Drop 2 now-redundant indexes (idx_park_date, idx_attendance_kingdom_date_mundane) that are strict prefixes of newly added covering indexes ## N+1 query fix — Kingdom and Park event listings - Replace correlated subqueries for RSVP going/interested counts with a single pre-aggregated LEFT JOIN subquery; reduces 2N+1 queries to 1 for any event listing (controller.Kingdom.php, controller.Park.php) ## Attendance partition columns — eliminate post-INSERT UPDATE - Add _computeDatePartitions() private helper in class.Attendance.php that computes date_year/month/week3/week6 via a direct MariaDB call (ensures WEEK(date,6) year-boundary correctness vs. any PHP formula) - Call helper from both AddAttendance() and SetAttendance() before save(), eliminating the post-INSERT UPDATE and fixing a pre-existing gap where SetAttendance() left partition columns stale on date edits ## Adjacent park date query — 2 queries to 1 - Merge two separate DataSet() calls in get_adjacent_park_dates() into a single UNION ALL query (model.Attendance.php) ## Navigation unblocking — Kingdom page - Add session_write_close() as first line of park_monthly_json(), park_averages_json(), and players_json() in controller.Kingdom.php; releases the PHP session file lock immediately so navigating away from a Kingdom page is never blocked by slow in-flight AJAX queries - Add AbortController in Kingdomnew_index.tpl wired to pagehide so both fetch() calls are cancelled the moment the user navigates away; pageshow handler with e.persisted guard re-creates the controller and re-triggers the averages fetch on bfcache restore Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
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
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ork_attendance,ork_park,ork_mundane,ork_event_calendardetail,ork_event_rsvp) plus removal of 2 now-redundant indexesAddAttendance()partition columns (date_year,date_month,date_week3,date_week6) now computed before INSERT, eliminating a post-INSERT UPDATE;SetAttendance()also fixed (previously left partition columns stale when the date changed)session_write_close()on all Kingdom AJAX endpoints releases the PHP session file lock immediately, so clicking away from a Kingdom page is never blocked by slow in-flight stats queries;AbortControlleron the client cancels both fetches on navigation and handles bfcache restore correctlyDetails
Database indexes (
db-migrations/2026-04-11-performance-indexes.sql)The Kingdom profile page fires several queries that scan
ork_attendanceover 26–52 week windows and group by computed columns (date_week3,date_month). Without covering indexes the planner falls back to full table scans on a 3.5M+ row table.New indexes:
ork_attendance(park_id, date, mundane_id)ork_attendance(kingdom_id, date, mundane_id, park_id)ork_attendance(date_year, date_week3, mundane_id)ork_attendance(date_year, date_month, mundane_id)ork_attendance(mundane_id, park_id, date)ork_park(kingdom_id, active)ork_mundane(park_id, suspended, active)ork_event_calendardetail(event_id, event_start)ork_event_rsvp(event_calendardetail_id, status)Dropped (now redundant prefixes of wider covering indexes):
idx_park_date,idx_attendance_kingdom_date_mundane. Migration usesCREATE/DROP INDEX IF NOT EXISTSthroughout — safe to re-run.N+1 RSVP fix (
controller.Kingdom.php,controller.Park.php)Before: Every event in the listing fired 2 correlated subqueries against
ork_event_rsvp(one forgoing, one forinterested). With 20 events on screen: 41 queries total for RSVP data.After: A single pre-aggregated
LEFT JOINsubquery computes all RSVP counts in one pass. 20 events: 1 query.Attendance partition columns (
system/lib/ork3/class.Attendance.php)Added
_computeDatePartitions()private helper that callsSELECT YEAR(), MONTH(), WEEK(date,3), WEEK(date,6)directly against MariaDB (required for WEEK mode 6 year-boundary correctness — no PHP formula is reliable for all edge cases). Called from bothAddAttendance()(beforesave(), eliminating the post-INSERT UPDATE) andSetAttendance()(fixing a pre-existing gap where date edits left partition columns stale).Adjacent park date query (
orkui/model/model.Attendance.php)get_adjacent_park_dates()replaced two sequentialDataSet()calls with oneUNION ALLquery.Navigation unblocking (
controller.Kingdom.php,Kingdomnew_index.tpl)PHP file-based sessions use exclusive locks. A slow
park_averages_jsonrequest holds the lock for its entire query duration, blocking any subsequent page load from the same browser.session_write_close()at the top of each JSON endpoint releases the lock immediately (these methods never write to the session). On the client, anAbortControllerwired topagehidecancels both in-flight fetches on navigation; apageshowhandler restores fetch capability on bfcache back/forward without leaving the stats columns stuck on spinners.Test plan
docker exec -i ork3-php8-db mariadb -u root -proot ork < db-migrations/2026-04-11-performance-indexes.sqlSHOW INDEX FROM ork_attendanceshows the 5 new indexes and does not showidx_park_dateoridx_attendance_kingdom_date_mundanedate_year/date_month/date_week3/date_week6update correctly in the DB row🤖 Generated with Claude Code