― 本番DBは、そんなに甘くない ―
スキーマ変更――それは、日々の開発の中で避けて通れない運命。
テーブルのカラムを追加したい。型を変更したい。インデックスを貼りたい。削除?できれば避けたい。
小さな変更に見えても、それが本番環境に与える影響は計り知れない。下手をすればシステム全体がダウン。数時間の復旧作業とユーザーからの問い合わせ地獄が待っている。
今回は、スキーマ変更で陥りがちな落とし穴と、安全なマイグレーションのための実践的手法を解説します。
スキーマ変更の落とし穴5選
1. カラム追加=軽い処理とは限らない
ALTER TABLE
でのカラム追加は一見シンプル。でもDBMSによっては、全件フルコピーが発生する。
特にMySQL(InnoDB)では古いバージョンでの変更が非常に重く、数百万件以上のテーブルでは処理が数分〜数時間かかることもある。
2. NULLの扱いを忘れる
新カラムに NOT NULL
をつけて追加すると、既存レコードに初期値が必要。指定を忘れると失敗するか、強制的にNULLが入る。アプリ側の処理でNULLが想定されていないと、NPE(NullPointerException)を誘発する危険も。
3. インデックス追加で書き込み性能が劣化
検索高速化のためのインデックス追加は正義――のように見えるが、更新・挿入時の書き込み負荷が大幅に増すことも。実はインデックスは「高速化のためのトレードオフ」。安易に乱用すると逆効果。
4. 型変更はデータ破壊の入り口
VARCHAR → INT
や DATETIME → DATE
のような型変更は、暗黙的な変換が行われてしまうことがある。失敗すればデータ欠損が発生。戻すのも地獄。
5. 削除系(DROP)は取り返しがつかない
テーブルやカラムの削除は最後の最後に。なぜなら、一度削除すれば、そのデータ構造をもとに戻すことはできない。バックアップがあっても、「使ってたコードが壊れた」なんてことはざらにある。
安全なマイグレーション手法とは?
では、スキーマ変更を安全に進めるにはどうすればいいのか?
鍵になるのは「段階的変更」「事前検証」「可逆性の確保」の3点です。
1. 段階的に進める(Expand → Migrate → Contract)
いわゆる「EMCパターン」とも呼ばれる手法。
- Expand:新カラムを追加(古いカラムはそのまま)
- Migrate:データを新カラムにコピー(並行稼働)
- Contract:古いカラムを削除(アプリコードも切り替え)
この流れなら、変更を段階的に進められ、失敗しても途中で巻き戻せる。
2. マイグレーションツールの活用
- Flyway や Liquibase、Railsの ActiveRecord::Migration など、コードでスキーマ変更を管理できるツールを使う。
- 手動のSQL変更は「誰が」「いつ」「何をしたか」が不明になりがち。バージョン管理とトレーサビリティを確保することが重要。
3. 事前にステージング環境で検証する
ステージング(検証)環境でデータ量や負荷を再現し、スキーマ変更の影響をシミュレーション。EXPLAIN
やANALYZE
で実行計画をチェックし、重くなるクエリを特定してから本番へ。
4. トランザクションを活用する(できる限り)
可能であれば、DDLをトランザクションで囲む。PostgreSQLでは多くのALTERがトランザクション内で安全に行えるが、MySQLでは非対応なものもあるため注意。
スキーマ変更は“運用フェーズの鬼門”
設計段階では見落としがちな「あとからの変更」。
でも実際には、アプリよりもDBの変更のほうがはるかにリスクが高い。
だからこそ、エンジニアは「DDLに対する慎重さ」「変更前後のシナリオ設計力」が問われる。
スキーマを変えるということは、
「データの住む世界を変える」ことに等しい。
その責任を自覚し、知識と手法をもって、慎重に、確実に進めよう。