メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
稼働中の MySQL データベースでのスキーマ変更は、些細なもの(小さなテーブルに NULL 許容の列を追加する)から危険なもの(毎秒 5 万件の書き込みを処理する 500GB のテーブルの列を変更する)まで幅があります。その違いは、MySQL がテーブルをロックするかどうか、そしてどれだけの時間ロックするかです。

ALTER TABLE の仕組み

MySQL の ALTER TABLE には、操作とバージョンに応じて 2 つのモードがあります。 再構築 DDL(従来の動作): MySQL は新しいスキーマで新しいテーブルを作成し、すべての行をコピーし、テーブルを入れ替えて、元のテーブルを削除します。その間ずっとテーブルは書き込みに対してロックされます。大きなテーブルでは数分から数時間です。 オンライン DDL: 多くの操作は、読み取りも書き込みもブロックせずに実行できます。MySQL はその場で変更を行うか、同時 DML を許可しながらバックグラウンドでテーブルを再構築します。特定の操作がどう動くかを調べるには、ALGORITHM 句と LOCK 句を明示的に追加します。要求した制約を満たせない場合、MySQL はステートメントを拒否します。

オンライン DDL のロックモード

ALGORITHM 句と LOCK 句は、MySQL が変更をどう実行するかを制御します。

速いものと遅いもの

ALGORITHM=INSTANT(MySQL 8.0)を使う操作は、テーブルのサイズに関係なくほぼ瞬時です。
  • 任意の位置への列の追加(MySQL 8.0.29 以降)
  • 仮想生成列の追加/削除
  • 列のデフォルト値の変更
ALGORITHM=COPY を必要とする操作は、その間ずっと書き込みをブロックします。
  • 列のデータ型の変更
  • 文字セットの変換
  • (全文インデックスの追加はこれに含まれません。INPLACE で実行されますが、常に少なくとも LOCK=SHARED が必要なため、読み取りは進み、書き込みはブロックされます。LOCK=NONE は ERROR 1846 で拒否されます)
ほとんどのインデックス追加は ALGORITHM=INPLACE, LOCK=NONE を使います。テーブルの再構築はバックグラウンドで行われ、DML は進みます。100GB のテーブルへのインデックス追加には時間がかかりますが、アプリケーションをブロックしません。

本番環境での大きなテーブルの移行

ロックするには大きすぎるテーブルで ALGORITHM=COPY を必要とする操作には、外部ツールを使います。

pt-online-schema-change(Percona Toolkit)

pt-osc はシャドウテーブルを作成し、行をバッチでコピーし、進行中の書き込みをトリガーで複製してから、テーブルを入れ替えます。アプリケーションのダウンタイムはありません。

gh-ost(GitHub)

gh-ost はトリガーの代わりにバイナリログを使うため、高い書き込み負荷の下でより信頼性があります。トラフィックの多いテーブルに選ばれるツールです。 どちらのツールも、テーブルに主キーが必要です。

マイグレーションツールとバージョン管理

スキーマ変更はバージョン管理されたマイグレーションファイルで追跡します。一般的なツールは次のとおりです。 各ツールは、どのマイグレーションが実行済みかを追跡するためにデータベース内にマイグレーションテーブルを保持するため、再実行は安全です。

よくある質問

テーブルをロックせずに列を追加できますか?

NULL 許容の列を任意の位置に追加する操作は ALGORITHM=INSTANT を使い、テーブルのサイズに関係なくミリ秒で完了します(MySQL 8.0.29 以降)。そうならない場合は、ALGORITHM=INPLACE, LOCK=NONE、または pt-osc か gh-ost を使ってください。

ALTER TABLE がテーブルをロックするかどうかはどう確認しますか?

ステートメントに ALGORITHM=INPLACE, LOCK=NONE を追加します。MySQL は可能ならロックせずに実行し、不可能ならエラーを返します。どちらにしても、推測なしに確定的な答えが得られます。
本番環境の大きなテーブルについて確信が持てない場合は、まずテーブルのコピーでテストしてください。

マイグレーションはトランザクション内で実行すべきですか?

DDL ステートメント(ALTER TABLE、CREATE INDEX、DROP TABLE)は MySQL で暗黙のコミットを引き起こし、ロールバックできません。BEGIN/COMMIT ブロックの中で実行しても保護にはなりません。トランザクションのロールバックに頼るのではなく、アプリケーションレベル(二重書き込み、フィーチャーフラグ)でロールバック戦略を計画してください。

トラブルシューティング

関連項目