Fixed slow database migration on large tables#27666
Conversation
ref https://linear.app/ghost/issue/BER-3565 ref https://linear.app/ghost/issue/BER-3542 Without {algorithm: 'auto'}, createAddColumnMigration emits ALGORITHM=COPY by default, which rebuilds the entire table. On a staging site with ~6M members_status_events rows this was slow enough to drop the MySQL connection mid-migration and prevent boot: [MIGRATE] Migration error: alter table members_status_events add batch_id varchar(24) null, algorithm=copy - Connection lost: The server closed the connection. Passing {algorithm: 'auto'} lets MySQL pick INSTANT for this nullable trailing-column add, making it metadata-only and effectively constant-time regardless of row count. Same conclusion reached in 2ea046c for the utm_ events column adds. Modifying the existing migration (rather than adding a follow-up) is required because the bad ALTER would otherwise run first on production before any later fix could take effect. The change is safe: schema.js is unchanged, the helper is idempotent, and sites that already ran the original version no-op on next deploy.
|
It looks like this PR contains a migration 👀 General requirements
Schema changes
Data changes
|
WalkthroughA database migration file for adding a 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ref https://linear.app/ghost/issue/BER-3565
ref https://linear.app/ghost/issue/BER-3542
ref #27615
ref https://ghost.slack.com/archives/CJBJ3MZFD/p1777972226248739
What changed
The migration
2026-04-29-12-13-44-add-batch-id-to-members-status-events.jsnow passes{algorithm: 'auto'}tocreateAddColumnMigration, so the emitted DDL isALTER TABLE members_status_events ADD COLUMN batch_id...omits the defaultALGORITHM=COPY.Why
createAddColumnMigrationdelegates tocommands.addColumn, which on MySQL appendsALGORITHM=COPYby default unless{algorithm: 'auto'}is explicitly passed.ALGORITHM=COPYrebuilds the entire table: it creates a new copy with the new column, copies every row across, then swaps it in. The cost is O(rows), and onmembers_status_events— which gets one row per member status change — this scales with the size of the member base.We hit this on a staging site with ~6M
members_status_eventsrows on boot:ALGORITHM=AUTOlets MySQL pick the best strategy. For a nullable trailing-column add on MySQL 8.0+ it picksINSTANT, which is a metadata-only change and effectively constant-time regardless of table size.This isn't a new conclusion — #25018 (
Added utm_ columns to events tables) introduced thealgorithmoption for exactly this reason after observing 60–250s migrations on a 2M-rowmembers_created_eventstable vs. 2–3s when MySQL was allowed to choose. All the column adds in that PR (and the canonicaladd-utm-fields.jsmigration) use{algorithm: 'auto'}.Why we're modifying an existing migration
We don't normally do this —
.agents/skills/create-database-migration/rules.mdstates migrations are immutable once onmain. We're making an exception here because:ALTER TABLEruns first when production upgrades through6.36/. Adding a fix in a later folder doesn't change that.schema.jsis untouched, so the integrity hash isn't bumped, and the end-state column definition is identical.createColumnMigrationcheckshasColumnand skips if the column already exists — so sites that already ran the original version on6.36.0simply no-op when redeployed against this commit. They don't see the migration twice and there's no schema drift between sites that ran the old version and sites that will run the new one.In short: existing sites that already migrated are unaffected; sites that haven't yet (including production) get the fast path.
Test plan
members_status_eventstablebatch_idalready exists🤖 Generated with Claude Code