本記事は、MySQL のオンラインスキーママイグレーションを gh-ost 経由で実行するオープンソースのデータベース DevSecOps ツール Bytebase が保守しています。
gh-ost と pt-online-schema-change は、Online DDL では ALTER をオンラインに保てないときに MySQL コミュニティが手を伸ばす 2 大ツールです。両者は同じ問題を逆向きのメカニズムで解き、同じ問題に異なる形でつまずきます。
1. アーキテクチャ
gh-ost (GitHub Online Schema Transmogrifier)
- トリガレス。非同期。
- binlog を追従して書き込みを捕捉する。Row-Based Replication を必要とし、通常レプリカから読む。
- ghost テーブルを構築し、ソースをチャンクごとにコピーし、binlog イベントを ghost に再生する。
- カットオーバーは明示的にトリガする短いメタデータロック。

pt-online-schema-change (Percona Toolkit)
- トリガベース。同期。
- ソースへの
INSERT、UPDATE、DELETEがトリガを発火し、同じトランザクション内で ghost テーブルへ書き込む。 - カットオーバーはアトミックな 2 テーブル
RENAME。 - MySQL 5.5+ で動き、外部キーを直接サポートする。
2 つの設計は同じコストを逆向きに払います。
pt-osc は ghost をソースと厳密に整合させます — レプリケーション遅延なし、非同期ギャップなし。代償として、ソースへのすべての書き込みがトリガオーバーヘッドを支払います。オーバーヘッドはカットオーバーで積み重なります: メタデータロックがトリガ駆動の書き込みと調整する必要があり、書き込みが多いとそれが運用上の懸念になります。pt-osc 自体は innodb_lock_wait_timeout=1 と lock_wait_timeout=60 を同梱し、ロック競合の被害者になり、加害者にならないよう自身を位置づけています。
gh-ost はソースの書き込みを安く保ち、整合性の作業を binlog の追従へ押し付けます。ghost テーブルは binlog ストリームの分だけソースから遅れます — トランザクション単位ではなく結果整合。
2. 機能比較
| 機能 | gh-ost | pt-online-schema-change |
|---|---|---|
| メカニズム | binlog 追従 (トリガ無し) | DML トリガ |
| 同期モデル | 非同期 | 同期 |
| ソース負荷 | 低い (レプリカから読む) | 高い (書き込みごとにトリガ) |
| 外部キー | 不可 — 削除して再作成 | 可 (--alter-foreign-keys-method) |
| レプリケーション | RBR 必須 | SBR/RBR どちらでも可 |
| スロットリング | レプリケーション遅延、フック、独自クエリ | レプリケーション遅延、コピー速度 |
| ランタイム制御 | Unix ソケット — throttle、postpone-cut-over-flag-file、チャンクサイズ調整、panic で中断 | 再起動のみ |
| カットオーバー | 手動トリガ。短いメタデータロック | アトミック RENAME。メタデータロックが並行書き込みと調整 |
| カットオーバーのスケジューリング | --postpone-cut-over-flag-file でオフタイムに合わせる | コピー完了次第カットオーバー |
| 一意キー | 変更前後で同じカラムを持つ NOT NULL のユニーク共有キー | テーブル上の PRIMARY KEY または UNIQUE INDEX |
| MySQL バージョン | 5.7+ | 5.0.2+ |
| 再開可能 | 不可 — プロセスが死ぬとマイグレーションは失われる | 可 — 直前の実行で --history、--nodrop-new-table、--nodrop-triggers を残せば --resume 可 |
| マネージドライフサイクル | 無し — リトライ、アラート、スケジュールは自前で用意 | 無し — 同上 |
選択肢に関係なく、運用面で 2 つの性質が効きます。再開可能性は不均一 — pt-osc は直前の実行で新テーブルとトリガを残しておけば (--nodrop-new-table、--nodrop-triggers、--history) --resume をサポートします。gh-ost には同等品が無く、プロセスが死ねばマイグレーションは失われます。どちらもマネージドではない — 監視、リトライ、アラート、スケジュールは周りに自分で配線する必要があります。
3. 良いところと悪いところ
| ツール | Pros | Cons |
|---|---|---|
| gh-ost | ソース負荷が低い。トリガ無し。Unix ソケット経由のライブ制御。カットオーバーを延期できる。 | 外部キー非対応。RBR 必須。MySQL 5.7+。プロセス死後の再開不可。 |
| pt-online-schema-change | 外部キーを保てる。広い MySQL バージョン対応。--resume で再開可能。発想がシンプル。 | トリガがすべての書き込みに負荷を加える。重ワークロード下でカットオーバーのロック競合。ランタイム制御が無い。 |
4. 使い分け
gh-ost を選ぶとき:
- ワークロードが書き込み中心で、ソースがトリガオーバーヘッドを許容できない。
- MySQL 5.7+ かつ Row-Based Replication で運用している。
- スロットリング、レプリカでのテスト、または自分が制御するカットオーバー時間帯が必要。
- 外部キーが無い、もしくは外部キーを削除して再作成してもよい。
pt-online-schema-change を選ぶとき:
- 外部キーが削除できないテーブルがある。
- MySQL 5.5 または 5.6 を使っている。
- ワークロードは軽〜中程度で、トリガオーバーヘッドが支配的にならない。
- レプリカに依存しないシンプルなセットアップが望ましい。
- 再開可能なマイグレーション (
--resume、--history、--nodrop-*) が必要。
5. 結論
両ツールとも同じ運用問題を解きます: 大きな MySQL テーブルをトラフィックを処理したまま ALTER する。並行する書き込みをどう扱うかで分岐します。gh-ost はソースを安く保ち、レプリケーション遅延とランタイムの複雑さを受け入れます。pt-osc は ghost を厳密に整合させ、トリガ負荷とカットオーバー競合を受け入れます。
決め手は通常具体的です。
- 削除できない外部キーがある → pt-osc。
- MySQL 5.5 / 5.6 → pt-osc。
- 重い書き込み → gh-ost。
いずれにせよ、ツールを自前のスケジュール、リトライ、監視で包んでください。どちらも、その周りでライフサイクルを扱うシステムから運用される前提です。