スキーマ変更の落とし穴と安全なマイグレーション手法

― 本番DBは、そんなに甘くない ―

スキーマ変更――それは、日々の開発の中で避けて通れない運命。
テーブルのカラムを追加したい。型を変更したい。インデックスを貼りたい。削除?できれば避けたい。

小さな変更に見えても、それが本番環境に与える影響は計り知れない。下手をすればシステム全体がダウン。数時間の復旧作業とユーザーからの問い合わせ地獄が待っている。

今回は、スキーマ変更で陥りがちな落とし穴と、安全なマイグレーションのための実践的手法を解説します。


スキーマ変更の落とし穴5選

1. カラム追加=軽い処理とは限らない

ALTER TABLE でのカラム追加は一見シンプル。でもDBMSによっては、全件フルコピーが発生する。
特にMySQL(InnoDB)では古いバージョンでの変更が非常に重く、数百万件以上のテーブルでは処理が数分〜数時間かかることもある。

2. NULLの扱いを忘れる

新カラムに NOT NULL をつけて追加すると、既存レコードに初期値が必要。指定を忘れると失敗するか、強制的にNULLが入る。アプリ側の処理でNULLが想定されていないと、NPE(NullPointerException)を誘発する危険も。

3. インデックス追加で書き込み性能が劣化

検索高速化のためのインデックス追加は正義――のように見えるが、更新・挿入時の書き込み負荷が大幅に増すことも。実はインデックスは「高速化のためのトレードオフ」。安易に乱用すると逆効果。

4. 型変更はデータ破壊の入り口

VARCHAR → INTDATETIME → DATE のような型変更は、暗黙的な変換が行われてしまうことがある。失敗すればデータ欠損が発生。戻すのも地獄。

5. 削除系(DROP)は取り返しがつかない

テーブルやカラムの削除は最後の最後に。なぜなら、一度削除すれば、そのデータ構造をもとに戻すことはできない。バックアップがあっても、「使ってたコードが壊れた」なんてことはざらにある。


安全なマイグレーション手法とは?

では、スキーマ変更を安全に進めるにはどうすればいいのか?
鍵になるのは「段階的変更」「事前検証」「可逆性の確保」の3点です。

1. 段階的に進める(Expand → Migrate → Contract)

いわゆる「EMCパターン」とも呼ばれる手法。

  1. Expand:新カラムを追加(古いカラムはそのまま)
  2. Migrate:データを新カラムにコピー(並行稼働)
  3. Contract:古いカラムを削除(アプリコードも切り替え)

この流れなら、変更を段階的に進められ、失敗しても途中で巻き戻せる。

2. マイグレーションツールの活用

  • FlywayLiquibase、Railsの ActiveRecord::Migration など、コードでスキーマ変更を管理できるツールを使う。
  • 手動のSQL変更は「誰が」「いつ」「何をしたか」が不明になりがち。バージョン管理とトレーサビリティを確保することが重要。

3. 事前にステージング環境で検証する

ステージング(検証)環境でデータ量や負荷を再現し、スキーマ変更の影響をシミュレーション。
EXPLAINANALYZEで実行計画をチェックし、重くなるクエリを特定してから本番へ。

4. トランザクションを活用する(できる限り)

可能であれば、DDLをトランザクションで囲む。PostgreSQLでは多くのALTERがトランザクション内で安全に行えるが、MySQLでは非対応なものもあるため注意。


スキーマ変更は“運用フェーズの鬼門”

設計段階では見落としがちな「あとからの変更」。
でも実際には、アプリよりもDBの変更のほうがはるかにリスクが高い

だからこそ、エンジニアは「DDLに対する慎重さ」「変更前後のシナリオ設計力」が問われる。

スキーマを変えるということは、
「データの住む世界を変える」ことに等しい

その責任を自覚し、知識と手法をもって、慎重に、確実に進めよう。


システム開発なんでもパートナー
システム開発なんでもパートナー

この記事を書いた人