MySQLにおけるpt-online-schema-changeの安全な運用ガイドと実践テクニック

運用上の制約と注意事項

Percona Toolkitのpt-online-schema-change(pt-osc)は、MySQLのテーブルロックを回避しながらスキーマ変更を行うための強力なツールですが、その内部動作(トリガーの利用とデータコピー)の特性上、厳格な制約と事前確認が求められます。

DDL操作の制限事項

  • 一意性インデックスの作成禁止: データ損失のリスクがあるため、新規にユニークインデックスを追加する操作は避けてください。関連するチェックオプション(--alter-check=noなど)を無効化することも厳禁です。
  • 主キーまたは一意性インデックスの必須要件: 対象テーブルに主キー、あるいは一意性インデックスが存在しない場合、pt-oscは利用できません。
  • 外部キー制約の非対応: 外部キーが設定されているテーブルに対する操作はサポートされていません。
  • 名前変更(RENAME)の禁止: テーブル名の変更、およびカラム名の変更は原則として禁止です。カラム名を変更する場合は、事前に--printで実行計画を確認し、意図しない動作にならないか慎重に検証する必要があります。
  • NOT NULL制約とデフォルト値: 新規カラムを追加する際、NOT NULLを指定する場合は必ずDEFAULT値を設定してください。
  • 主キーの削除禁止: 既存の主キーを削除する操作は行えません。
  • CHANGE COLUMNの非サポート: カラム名と型を同時に変更するCHANGE COLUMNは、データ損失のリスクが高いためオンライン変更ではサポートされていません。

環境・リソース要件とベストプラクティス

  • 容量の事前確認: pt-oscは元のテーブルと同等のデータを一時的にコピーするため、ディスク容量に十分な空き(対象テーブルサイズの倍以上)があるか確認してください。また、Row-based binlogが大量に生成されるため、Binlogの保存領域もチェックが必要です。
  • 実行タイミング: 負荷がかかる操作であるため、必ず業務のオフピーク時間帯に実行してください。
  • トリガーの競合回避: 対象テーブルに既存のトリガーが設定されている場合、pt-oscは利用できません。
  • InnoDB設定の最適化: 高並列書き込み環境では、innodb_autoinc_lock_mode=2に設定することを推奨します。これにより、AUTO_INCREMENTロックによる待機やデッドロックの発生を抑制できます。
  • レプリケーション構成の一致性: マスタとスレーブのテーブル構造は完全に一致している必要があります。構造が異なる場合、スレーブ側で予期せぬスキーマ上書きが発生する可能性があります。
  • 文字コードの明示: 日本語や中国語などのマルチバイト文字を含むコメントを追加・変更する際は、必ず--charset=utf8mb4(またはutf8)を指定し、文字化けを防いでください。

異常終了時のリカバリ

pt-oscが異常終了した場合、新規作成された一時テーブル(_new)と、元テーブルに設定されたトリガーは自動では削除されません。再開や手動クリーンアップを行う際は、必ず先にトリガーを削除してから一時テーブルをドロップしてください。順序を誤ると、元テーブルへの書き込みが失敗します。

また、誤ってスレーブノードで実行してしまった場合、処理が完了するまでは中断せずそのまま完了させてから元の状態に戻すか、未完了の場合は作成された一時テーブルとトリガーを手動で削除して整合性を保ってください。

実践的な実行コマンド例

以下の例では、マスタデータベースに対して実行することを前提としています。接続エラーを避けるため、--hostにはlocalhost(Unixソケット接続)ではなく、127.0.0.1(TCP/IP接続)または実際のIPアドレスを指定することを推奨します。

1. インデックスの削除

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --check-interval=5 --chunk-size=2000 --chunk-time=1 \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "DROP INDEX idx_campaign_status" \
  D=ecommerce_db,t=campaign_metrics \
  --print --execute

2. 単一インデックスの追加

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --check-interval=5 --chunk-size=2000 --chunk-time=1 \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "ADD INDEX idx_region_code (region_code)" \
  D=ecommerce_db,t=campaign_metrics \
  --print --execute

3. 複合インデックスの作成

複数カラムを組み合わせたインデックスを追加する例です。データ量が多いテーブルでも、チャンクサイズを調整することで安全に実行できます。

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --check-interval=5 --chunk-size=2000 --chunk-time=1 \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "ADD INDEX idx_user_action_log (user_id, action_type, created_at)" \
  D=ecommerce_db,t=user_activity_logs \
  --print --execute

4. カラムの追加(NOT NULL制約あり)

NOT NULL制約を付与する場合は、DEFAULT値の指定が必須です。

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "ADD COLUMN is_premium TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'プレミアム会員フラグ'" \
  D=ecommerce_db,t=customer_profiles \
  --print --execute

5. カラムの削除

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "DROP COLUMN legacy_tracking_id" \
  D=ecommerce_db,t=order_details \
  --print --execute

6. カラムのデータ型変更(MODIFY)

time pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --max-lag=3 --nocheck-replication-filters \
  --max-load="Threads_running:100" --critical-load="Threads_running:200" \
  --alter "MODIFY COLUMN total_amount DECIMAL(15,2) NOT NULL DEFAULT 0.00" \
  D=ecommerce_db,t=order_details \
  --print --execute

7. CHANGE COLUMN によるリネームの失敗例

pt-oscはCHANGE COLUMNによるカラム名の変更を安全ではないと判断し、デフォルトでブロックします。以下のコマンドを実行すると、チェックエラーが発生して処理が中断されます。

pt-online-schema-change \
  --user="dba_admin" --password="SecurePass!2024" \
  --host="10.0.1.50" --port=3306 --charset="utf8mb4" \
  --alter "CHANGE COLUMN old_status_name new_status_name VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'ステータス名'" \
  --check-alter --max-lag=3 --nocheck-replication-filters \
  D=ecommerce_db,t=system_configs \
  --print --execute

エラー出力例:

--alter appears to rename these columns:
  old_status_name to new_status_name
The tool should handle this correctly, but you should test it first because if it fails the renamed columns' data will be lost!  Specify --no-check-alter to disable this check and perform the --alter.
`ecommerce_db`.`system_configs` was not altered.
--check-alter failed.

タグ: MySQL pt-online-schema-change PerconaToolkit DDL データベース管理

10月16日 06:53 投稿