2.

ALTER TABLE カラム定義変更完全ガイド (MySQL/PG/Online DDL)

編集
この記事の要点
  • MySQL/MariaDB: ALTER TABLE t MODIFY col VARCHAR(255)
  • PostgreSQL: ALTER TABLE t ALTER COLUMN col TYPE VARCHAR(255)
  • リネーム: MySQL CHANGE old_name new_name 型 / PG RENAME COLUMN
  • デフォルト値: SET DEFAULT / DROP DEFAULT
  • 巨大テーブルはオンライン DDL(pt-online-schema-change / gh-ost)で停止時間ゼロ

MySQL での ALTER TABLE

型・属性の変更(MODIFY)

-- 型変更
ALTER TABLE users MODIFY name VARCHAR(255);

-- 型 + NOT NULL + DEFAULT 一括
ALTER TABLE users MODIFY name VARCHAR(255) NOT NULL DEFAULT '';

-- カラム位置移動
ALTER TABLE users MODIFY name VARCHAR(255) AFTER id;
ALTER TABLE users MODIFY name VARCHAR(255) FIRST;

-- 文字コード変更
ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

リネーム + 型変更(CHANGE)

-- 名前を変える時は CHANGE
ALTER TABLE users CHANGE username name VARCHAR(255) NOT NULL;
-- old_name new_name 型 ... の順

-- MySQL 8.0+ は RENAME COLUMN もサポート
ALTER TABLE users RENAME COLUMN username TO name;

-- 複数まとめて変更
ALTER TABLE users
    MODIFY name VARCHAR(255) NOT NULL,
    CHANGE email mail VARCHAR(255) NOT NULL,
    ADD COLUMN phone VARCHAR(20),
    DROP COLUMN deleted_at;

デフォルト値の変更

-- デフォルト値追加
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';

-- デフォルト値削除
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;

-- NOT NULL 追加(既存 NULL があるとエラー → 先に UPDATE で埋める)
UPDATE users SET status = 'active' WHERE status IS NULL;
ALTER TABLE users MODIFY status VARCHAR(20) NOT NULL DEFAULT 'active';

-- NOT NULL 削除
ALTER TABLE users MODIFY status VARCHAR(20) NULL;

PostgreSQL での ALTER TABLE

-- 型変更
ALTER TABLE users ALTER COLUMN name TYPE VARCHAR(255);

-- USING で明示変換が必要なケース
ALTER TABLE users ALTER COLUMN age TYPE INTEGER USING age::INTEGER;
ALTER TABLE logs ALTER COLUMN created_at TYPE TIMESTAMPTZ
    USING created_at AT TIME ZONE 'UTC';

-- リネーム
ALTER TABLE users RENAME COLUMN username TO name;

-- デフォルト値
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;

-- NOT NULL
ALTER TABLE users ALTER COLUMN status SET NOT NULL;
ALTER TABLE users ALTER COLUMN status DROP NOT NULL;

-- 一気に複数操作
ALTER TABLE users
    ALTER COLUMN name TYPE VARCHAR(255),
    ALTER COLUMN status SET DEFAULT 'active',
    ALTER COLUMN status SET NOT NULL;

SQL Server / Oracle

-- SQL Server
ALTER TABLE users ALTER COLUMN name VARCHAR(255) NOT NULL;
EXEC sp_rename 'users.username', 'name', 'COLUMN';
ALTER TABLE users ADD CONSTRAINT df_status DEFAULT 'active' FOR status;

-- Oracle
ALTER TABLE users MODIFY (name VARCHAR2(255) NOT NULL);
ALTER TABLE users RENAME COLUMN username TO name;
ALTER TABLE users MODIFY (status DEFAULT 'active');
ALTER TABLE users MODIFY (status DEFAULT NULL);   -- DEFAULT 削除

カラム追加・削除

-- 追加
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users ADD COLUMN phone VARCHAR(20) AFTER email;    -- MySQL
ALTER TABLE users ADD COLUMN phone VARCHAR(20) DEFAULT NULL;

-- 削除
ALTER TABLE users DROP COLUMN phone;

-- 複数追加(MySQL)
ALTER TABLE users
    ADD COLUMN phone VARCHAR(20),
    ADD COLUMN address TEXT,
    ADD COLUMN birthdate DATE;

巨大テーブルでの問題点

10 億行あるテーブルで ALTER TABLE を実行すると:

  • 処理に数時間〜数日かかる
  • その間テーブルが書き込みロックされる(DB により差)
  • 失敗するとロールバックでさらに時間
  • レプリケーション遅延

MySQL Online DDL の進化

バージョン状況
5.5 以前テーブル全体ロック → 読み書き全停止
5.6Online DDL 導入。インデックス追加等は読み書き継続可能
5.7Online DDL 対象拡大
8.0INSTANT ADD COLUMN(瞬時カラム追加、データ書き換えなし)
8.0.29+INSTANT DROP / RENAME カラム
-- MySQL 8.0+ の INSTANT は数ミリ秒で完了
ALTER TABLE big_table ADD COLUMN flag TINYINT, ALGORITHM=INSTANT;

-- アルゴリズムを明示
-- ALGORITHM=COPY     - 旧式、全行コピー(最遅、最確実)
-- ALGORITHM=INPLACE  - 既存テーブルを変更、読み書き継続可(多くの場合)
-- ALGORITHM=INSTANT  - メタデータのみ変更、即時完了(限定操作)

-- LOCK レベル
-- LOCK=NONE      - 読み書きとも継続可
-- LOCK=SHARED    - 読みのみ可
-- LOCK=EXCLUSIVE - 全停止

ALTER TABLE big_table
    ADD COLUMN flag TINYINT,
    ALGORITHM=INPLACE, LOCK=NONE;

pt-online-schema-change(Percona Toolkit)

MySQL の Online DDL でも対応できない変更(型変換等)には、pt-online-schema-change または gh-ost を使います。

# 仕組み: 新テーブルを作る → トリガで同期 → 旧データをコピー → アトミック RENAME

# インストール (Ubuntu)
sudo apt install percona-toolkit

# ALTER 実行
pt-online-schema-change \
  --alter "MODIFY name VARCHAR(500) NOT NULL" \
  --execute \
  h=localhost,D=mydb,t=users,u=root,p=secret

# dry-run(実行しない確認のみ)
pt-online-schema-change \
  --alter "MODIFY name VARCHAR(500) NOT NULL" \
  --dry-run \
  h=localhost,D=mydb,t=users

# 注意:
#   外部キーで参照されているテーブルは制約処理が複雑
#   --alter-foreign-keys-method=auto / drop_swap / rebuild_constraints

gh-ost(GitHub 製)

pt-online-schema-change の代替。トリガを使わずbinlog を読んで同期するため、本番への影響が小さいのが特徴:

gh-ost \
  --user=root --password=secret \
  --host=localhost \
  --database=mydb \
  --table=users \
  --alter="MODIFY name VARCHAR(500) NOT NULL" \
  --execute

# dry-run
gh-ost ... --execute=false

# レプリカでスロットリング自動制御
gh-ost ... --max-lag-millis=1500

PostgreSQL での巨大テーブル変更

-- PostgreSQL 11+ : 多くの ALTER がインスタント完了
-- DEFAULT 追加もテーブル書換不要
ALTER TABLE big_table ADD COLUMN flag BOOLEAN DEFAULT FALSE NOT NULL;

-- 型変更で全行書換が起きるケース(重い)
ALTER TABLE big_table ALTER COLUMN id TYPE BIGINT;
-- → テーブル全コピー、ACCESS EXCLUSIVE ロック

-- 安全策: 一時カラム経由
ALTER TABLE big_table ADD COLUMN id_new BIGINT;
UPDATE big_table SET id_new = id WHERE id_new IS NULL;  -- 分割実行
-- ... トリガで新規 INSERT も同期 ...
ALTER TABLE big_table DROP COLUMN id;
ALTER TABLE big_table RENAME COLUMN id_new TO id;

-- pg_repack でテーブル再構成(要拡張)
-- pg_repack -t big_table -d mydb

Laravel マイグレーションでの変更

// doctrine/dbal が必要
// composer require doctrine/dbal

Schema::table('users', function (Blueprint $table) {
    $table->string('name', 255)->nullable()->change();      // 型・NULL 変更
    $table->renameColumn('username', 'name');                // リネーム
    $table->string('status')->default('active')->change();   // デフォルト値
    $table->dropColumn('deleted_at');
});

変更前のチェックリスト

  • 本番のテーブル行数を EXPLAIN で確認(数千万行以上ならオンライン DDL ツール検討)
  • レプリケーション遅延が許容範囲か
  • 外部キーが絡む場合は手順を整理
  • 失敗時のロールバック計画
  • 新カラムに NOT NULL を付けるなら先にデータを埋めるか DEFAULT を指定
  • 本番投入前にステージング環境で時間計測

FAQ

Q: ALTER TABLE が終わらない
A: SHOW PROCESSLIST で進捗確認。中止したい場合は KILL [thread_id]。途中キャンセル後はテーブル整合性確認を。

Q: NOT NULL を後から追加してエラー
A: 既存に NULL 行があると失敗。先に UPDATE t SET col = 'デフォルト値' WHERE col IS NULL を実行してから ALTER。

Q: カラム順序を変えたい(MySQL)
A: MODIFY col 型 AFTER 他のカラム または FIRST。MySQL のみ対応。PostgreSQL は順序変更不可(不要な設計上の理由)。

Q: 巨大テーブルで型変更を確実に安全に
A: 新カラム追加 → トリガ / アプリで二重書き込み → バッチで埋め戻し → 旧カラム削除、の段階的アプローチが最も安全。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. テーブル作成
  2. カラムの定義変更
  3. カラム名の変更
  4. カラム追加 / 削除
  5. インデックスの作成
  6. インデックスの削除
  7. AUTO_INCREMENTの仕様について
  8. AUTO_INCREMENTの追加と確認方法
  9. 外部キーの追加/削除と制約名の確認方法

最近更新/作成されたページ