ALTER TABLE完全ガイド:構文・ロック・性能・移行のベストプラクティス
はじめに
ALTER TABLE文はリレーショナルデータベースにおけるスキーマ変更の中核を担う命令です。列の追加・削除・変更、制約(PRIMARY KEY、FOREIGN KEY、UNIQUE、CHECK)の追加・削除、インデックス操作、テーブル名やカラム名の変更など、運用中のデータ構造を変えるために不可欠です。一方でCREATEやSELECTとは異なり、ALTER TABLEは大きなロックやテーブル書き換えを伴い、サービス停止やパフォーマンス劣化を招くことがあります。本コラムでは主要データベース(MySQL、PostgreSQL、SQL Server、Oracle)での振る舞い、構文の違い、オンラインDDL、トランザクション性、パフォーマンス対策、運用上のベストプラクティスを深掘りします。
ALTER TABLEの基本操作と意味
代表的な操作は次の通りです。ADD COLUMN、DROP COLUMN、ALTER/MODIFY COLUMN(型変更、NULL/NOT NULL変更、デフォルト設定)、RENAME(テーブル/カラム名変更)、ADD/DROP CONSTRAINT、ADD/DROP INDEX、PARTITION操作。これらは「スキーマの変更」を表し、実行時にテーブルのメタデータやデータ領域に対してさまざまな処理を行います。データ量やDBエンジンの実装により、即時適用かテーブル全体の書き換え(フルコピー)か、オンラインで行えるかが変わります。
主要DBMSごとの挙動の違い
データベースごとにALTER TABLEの性質は大きく異なります。以下は代表的な挙動のまとめです。
- MySQL(特にInnoDB): 多くのALTER TABLEはテーブルの再作成を伴い、旧来の挙動ではテーブルロックや長時間のダウンタイムを招きました。MySQL 5.6以降・InnoDBではオンラインDDLのサポートが拡張され、MySQL 5.7/8.0ではALGORITHM=INPLACEやLOCK=NONE/SHAREDを指定してより非ブロッキングで実行できるものが増えています。ただし、ADD COLUMN with default(非NULL)や一部の型変更は依然としてテーブル書き換えを必要とする場合があります。またMySQLの多くのDDLは暗黙コミットが発生し、ロールバックできません。
- PostgreSQL: ALTER TABLEは基本的にトランザクション内で実行可能で、失敗した場合はロールバックできます。PostgreSQL 11以降、DEFAULT値の追加で全行を書き換えずに済む最適化(デフォルトをカタログに記録し、読み出し時に適用)などが導入されました。型変更やNOT NULL追加(既存のNULLチェックが必要な場合)はテーブル全体の検査や書き換えが発生します。VACUUMや統計情報の影響も考慮が必要です。
- SQL Server: 多くのALTER TABLE操作はトランザクショナルで、スキーマ変更をロールバック可能です。オンラインでのインデックス再構築や一部の列変更(Enterprise版や特定のオプション)で非同期処理が可能です。ただし、操作の内容によっては排他ロックや長時間のメタデータロックが発生します。
- Oracle: Oracleの多くのDDLは実行時にコミットされ、ロールバック不可です。オンラインリオグナイゼーション(DBMS_REDEFINITION)を使うことでダウンタイムを抑えつつスキーマ変更が可能ですが、事前の準備や権限、運用手順が必要です。
トランザクション性とロックの実務的理解
運用で特に重要なのはALTER TABLE実行中のロックとトランザクション性です。PostgreSQLはDDLがトランザクションに組み込まれるため安全性が高い反面、長時間のスキーマ変更はトランザクション保持によりVACUUMやクエリに影響します。MySQLは多くのDDLで暗黙コミットが発生するため、その瞬間に接続状態が変わり、トランザクション中の変更が確定します。SQL Serverは概してトランザクション対応ですが、システムバージョンやエディションによりオンライン処理の可否が異なります。OracleはDDLがコミットされる点を念頭に置き、事前バックアップや再実行手順を整備する必要があります。
オンラインDDLとZero-downtime戦略
スキーマ変更でダウンタイムを減らすテクニックは複数存在します。MySQLでは公式のALGORITHM/LOCKオプションを試し、不可ならpt-online-schema-changeやGitHubのgh-ostのようなツールでテーブルをオンライン移行します。これらは新しいテーブルを作成して差分を投げ、最終同期待ちでスワップする手法です。PostgreSQLでは、新しい列をADDしてアプリ側で二重書き込みを行い、後で旧列を削除するなど段階的変更が有効です。SQL ServerやOracleでもオンラインインデックスやDBMS_REDEFINITIONを活用できます。一般原則として、変更は小さく段階的に行い、読み書きの互換性を保つことが重要です。
パフォーマンスとデータ量の影響
ALTER TABLEのコストは主にデータ量、カラム数、インデックス数、行長、ストレージのIO性能に依存します。大規模なテーブルでのフルコピーはIOとログを大量に消費し、レプリケーションラグやバックアップウィンドウに影響します。実行前に次を確認してください:テーブル行数と平均行サイズ、インデックスの数、レプリケーションの状態、実行時間の見積もり(テスト環境でのリハーサル)、監視・アラート設定。
ベストプラクティス
- 変更を小さなステップに分割する(例:新列追加→アプリで利用→古い列削除)。
- メンテナンスウィンドウを確保し、事前に緊急ロールバック手順を用意する(バックアップやスキーマ差分)。
- ステージング環境で必ず実行時間と副作用を検証する。特にレプリケーション環境ではラグをチェックする。
- オンラインDDLが利用可能ならまず試すが、不可の場合はツール(pt-online-schema-change/gh-ost、Postgresのpg_repackなど)を検討する。
- 統計情報を更新し、インデックスを必要最小限に保つ。ALTER後はANALYZE/UPDATE STATISTICSを実行する。
- マイグレーション管理ツール(Liquibase、Flyway)でスキーマ変更をコード化し、履歴管理する。
よくある落とし穴と回避策
代表的な落とし穴には以下があります:アプリケーションの互換性不足(NULL/NOT NULLやデフォルトの違い)、外部キー検証による長時間ロック、レプリケーションの遅延、想定外のテーブル再作成、DDLのロールバック不可。回避策は事前の互換性チェック、段階的リリース、データ検証クエリの実行、レプリケーションの事前確認です。
実例:MySQLでの安全なカラム追加手順
大容量テーブルにNOT NULLでデフォルトを設定する必要がある場合、直接ALTER TABLEで追加するとフルコピーが走ることが多い。安全な手順例:
- 1) NULL許容でデフォルトなしの新しいカラムを追加する(オンラインで軽微)。
- 2) バッチでアプリケーションもしくはSQLで既存行に値を設定する(段階的に実行して負荷を調整)。
- 3) カラムにNOT NULL制約とデフォルトを設定する(短時間で済む場合が多い)。
ツールと自動化
運用で有用なツール:pt-online-schema-change(Percona)、gh-ost(GitHub, MySQL専用)、pg_repack(PostgreSQLの再算出・再配置ツール)、Liquibase/Flyway(マイグレーション管理)。これらは各DBの特性に合わせた安全なロールアウトを支援しますが、必ずテストを行い副作用を確認してください。
監視と検証
ALTER TABLE実行中は次を監視しましょう:IOPS/レイテンシ、レプリケーションラグ、ロングトランザクションやロックの待ち、ログの急増(WAL/redoログ)。また、実施後はクエリプランやパフォーマンスを比較し、統計の更新を行って最適化を促します。
まとめ
ALTER TABLEは強力ですが慎重に扱う必要があります。各DBMSの特性を理解し、オンラインDDLや外部ツール、段階的な変更戦略を活用することでダウンタイムとリスクを最小化できます。運用環境では必ず事前テスト、バックアップ、監視、ロールバックプランを用意して実行してください。
参考文献
- MySQL Reference Manual — ALTER TABLE
- InnoDB Online DDL Operations
- pt-online-schema-change (Percona)
- gh-ost — GitHub
- PostgreSQL Documentation — ALTER TABLE
- Microsoft Docs — ALTER TABLE (Transact-SQL)
- Oracle Database Documentation (DBMS_REDEFINITIONなど)
- Liquibase — Database schema change management
- Flyway — Database migrations


