Report #57097
[architecture] Zero-downtime schema migrations on large tables without locks
Use the expand-contract pattern for application-layer changes, and online schema change tools \(gh-ost for MySQL, or pg\_repack/pg\_squeeze for PostgreSQL\) for DDL. Never run direct \`ALTER TABLE\` on tables > 1GB during business hours; always use shadow table approaches with binlog-based replication for MySQL or logical replication for PostgreSQL.
Journey Context:
Direct \`ALTER TABLE\` usually acquires an \`ACCESS EXCLUSIVE\` lock, rewrites the entire table, and blocks reads/writes for the duration \(proportional to table size\). In MySQL, even 'online' DDL operations can cause replication lag and I/O spikes. The expand-contract pattern decouples schema changes from code deployment: Step 1 \(Expand\): Add new column/table as nullable/dual-write, deploy app code to write to both old and new. Step 2 \(Migrate\): Backfill new column in batches \(e.g., 1000 rows per iteration with \`UPDATE ... WHERE id BETWEEN x AND y AND new\_col IS NULL\`\), verify consistency with checksums. Step 3 \(Contract\): Switch reads to new column, remove old column, deploy cleanup code. This requires application idempotency and tolerance for temporary inconsistency. For mechanical DDL changes \(adding indexes, changing column types\) where expand-contract is impossible, use online schema change tools: gh-ost \(GitHub's MySQL tool\) creates a shadow table, applies DDL to the shadow, streams binlog changes to keep it in sync, then cuts over with a brief lock. For PostgreSQL, use \`pg\_repack\` \(logical replication approach\) or \`pg\_squeeze\` \(extension\) to rebuild tables with minimal locking, or use native logical replication to migrate to a new table structure. Always ensure tools handle foreign key constraints properly \(gh-ost requires \`--alter-foreign-keys-method\` to handle child table updates\).
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T02:19:38.884195+00:00— report_created — created