|
| 1 | +--- |
| 2 | +title: MySQL Schema Migration Best Practice |
| 3 | +author: Adela |
| 4 | +updated_at: 2025/12/09 18:00:00 |
| 5 | +feature_image: /content/blog/mysql-schema-migration-best-practice/banner.webp |
| 6 | +tags: Industry |
| 7 | +description: A guide to MySQL schema migration best practice. |
| 8 | +--- |
| 9 | + |
| 10 | +Schema changes are a normal part of software development. Columns get added, data types change, indexes appear or disappear. But in MySQL, even a simple `ALTER TABLE` can block queries, slow down replicas, or cause downtime if not planned well. |
| 11 | + |
| 12 | +This guide explains a practical way to manage MySQL schema migrations - simple to follow and focused on the MySQL behaviors that matter in real production environments. |
| 13 | + |
| 14 | + |
| 15 | +## Core Best Practices |
| 16 | + |
| 17 | +These ideas apply broadly to database migrations. They form a reliable foundation before considering MySQL-specific behavior. |
| 18 | + |
| 19 | +### Keep schema changes traceable |
| 20 | + |
| 21 | +Teams need a clear record of how the database evolves. |
| 22 | +Whether you use Git, a migration tool, or a structured changelog, the key is: |
| 23 | + |
| 24 | +> **Every schema change should be recorded, reviewable, and reproducible.** |
| 25 | +
|
| 26 | +This prevents hidden production changes and environment drift. |
| 27 | + |
| 28 | +### Use small, incremental, backward-compatible steps |
| 29 | + |
| 30 | +A safer approach is the known pattern: |
| 31 | + |
| 32 | +1. **Expand** - add new columns or tables without removing anything |
| 33 | +2. **Migrate** - backfill data and update application logic |
| 34 | +3. **Contract** - remove old fields only after everything is stable |
| 35 | + |
| 36 | +The contract step usually happens days later because dropping a column is irreversible. Teams wait until all parts of the system clearly use the new structure and real traffic shows no issues. |
| 37 | + |
| 38 | +### Automate checks and workflows |
| 39 | + |
| 40 | +Automation reduces mistakes and increases consistency: |
| 41 | + |
| 42 | +- **SQL review rules:** catch unsafe SQL before execution. |
| 43 | +- **CI checks:** run automated tests and static checks on migration scripts. |
| 44 | +- **Staging verification:** confirm the migration behaves correctly with realistic data. |
| 45 | +- **Consistent environment promotion:** apply migrations in the same order across Dev -> Test -> Prod. |
| 46 | + |
| 47 | +These steps create a predictable path from development to production. |
| 48 | + |
| 49 | +## Key MySQL Behaviors to Know |
| 50 | + |
| 51 | +MySQL has several characteristics that directly affect schema migrations. Understanding these early avoids surprises. |
| 52 | + |
| 53 | +- **Some schema changes rebuild the whole table** - Certain `ALTER TABLE` operations create a new copy of the table, which can slow things down or block writes. |
| 54 | + |
| 55 | +- **Metadata locks can block queries** - A schema change must wait for ongoing queries to finish. While waiting, it can block new queries behind it. |
| 56 | + |
| 57 | +- **Large changes can cause replica lag** - Big ALTERs or heavy backfills often make replicas fall behind, affecting reads and failover. |
| 58 | + |
| 59 | +- **Some MySQL features are harder to modify** - Examples include ENUM changes, JSON indexes, and FOREIGN KEYS on large tables. |
| 60 | + |
| 61 | +## A Practical Migration Workflow for MySQL |
| 62 | + |
| 63 | +This workflow reflects what developers actually do, with MySQL’s behavior in mind. |
| 64 | + |
| 65 | +### 1 Plan the change carefully |
| 66 | + |
| 67 | +Before writing SQL, understand the impact: |
| 68 | + |
| 69 | +- Will the operation **rebuild** the table? |
| 70 | +- How **large** is the table in production? |
| 71 | +- Are there **long-running queries** that could block the migration? |
| 72 | +- How will **replicas** respond? |
| 73 | +- Can the work be **split** into smaller, safer steps? |
| 74 | + |
| 75 | +A few minutes of planning prevents many issues later. |
| 76 | + |
| 77 | +### 2 Write simple and predictable migration scripts |
| 78 | + |
| 79 | +Good migration scripts are easy to understand and review: |
| 80 | + |
| 81 | +- One logical change at a time |
| 82 | +- Clear and descriptive naming |
| 83 | +- Avoid mixing schema and heavy data updates |
| 84 | +- Break changes into steps when needed (for example, add column -> backfill -> update code) |
| 85 | + |
| 86 | +Older MySQL versions often rebuild tables when adding a column with a default value, so separating operations reduces risk. |
| 87 | + |
| 88 | +### 3 Test the migration with real impact in mind |
| 89 | + |
| 90 | +Testing should consider both correctness and performance: |
| 91 | + |
| 92 | +- Run first in Dev, then in Staging |
| 93 | +- Use staging data that matches production size |
| 94 | +- Measure how long the migration takes |
| 95 | +- Observe whether replicas fall behind |
| 96 | +- Test application behavior on the changed tables |
| 97 | + |
| 98 | +A change that seems instant on a local machine may take minutes - or more - on real data. |
| 99 | + |
| 100 | +### 4 Deploy with caution and observability |
| 101 | + |
| 102 | +During deployment: |
| 103 | + |
| 104 | +- Promote the migration across environments in order |
| 105 | +- Check for blocking queries before running DDL |
| 106 | +- Monitor: |
| 107 | + - metadata lock waits |
| 108 | + - slow queries |
| 109 | + - replica lag |
| 110 | + |
| 111 | +Because MySQL DDL is not transactional, rolling back a schema change is usually not possible. To reduce risk: |
| 112 | + |
| 113 | +- Use roll-forward migrations to fix issues quickly |
| 114 | +- Keep reliable backups and test restore procedures |
| 115 | +- Make data migrations reversible when possible |
| 116 | + |
| 117 | +A careful rollout with a clear recovery plan makes deployments much safer. |
| 118 | + |
| 119 | +## Tooling and Zero-Downtime Options |
| 120 | + |
| 121 | +Some tools exist specifically to work around MySQL’s migration challenges. |
| 122 | + |
| 123 | +### [pt-online-schema-change](https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html) |
| 124 | + |
| 125 | +Creates a shadow table and copies data gradually, reducing locking. Useful for large and busy tables. |
| 126 | + |
| 127 | +### [gh-ost](https://github.com/github/gh-ost) |
| 128 | + |
| 129 | +Uses binary logs instead of triggers and works well on high-write workloads. |
| 130 | +Often safer for large-scale online schema changes. |
| 131 | + |
| 132 | +### [Native MySQL Online DDL](https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl.html) |
| 133 | + |
| 134 | +MySQL 8.0 supports more fast operations, but testing is still required to avoid unexpected behavior. |
| 135 | + |
| 136 | +### Migration frameworks and workflow tools |
| 137 | + |
| 138 | +These tools help manage versioning, ordering, and execution of schema changes: |
| 139 | + |
| 140 | +- [Flyway](https://flywaydb.org/) |
| 141 | + Tracks versions and applies schema changes in order. |
| 142 | + |
| 143 | +- [Liquibase](https://www.liquibase.org/) |
| 144 | + Uses declarative change sets and supports rollback logic and more structured migration workflows. |
| 145 | + |
| 146 | +- [Bytebase](/) |
| 147 | + Provides a workflow for schema changes, SQL review, and environment promotion, supporting both GUI-based changelog and GitOps modes. |
| 148 | + Also integrates with gh-ost for safer online schema changes on large tables. |
| 149 | + |
| 150 | +## Conclusion |
| 151 | + |
| 152 | +Safe MySQL schema migration comes from understanding how MySQL behaves and following a clear, consistent workflow. With small changes, proper testing, and basic awareness of locking and replication, teams can update their schemas with far less risk and uncertainty. |
0 commit comments