一、核心原理(必读)

为什么不能直接 ALTER TABLE

在 MySQL(尤其是 InnoDB 引擎)中,不是所有 ALTER TABLE 操作都能“在线”完成。很多操作会触发 “表重建”(Table Rebuild),即:

  1. 创建一张新结构的临时表

  2. 逐行拷贝原表所有数据到新表

  3. 删除原表

  4. 将临时表重命名为原表名

这个过程在早期 MySQL 中是 完全锁表的(Copy Table),即使后来有了 Online DDL,仍有大量操作不支持“无锁”。

不同 MySQL 版本的行为对比

1. MySQL 5.6 及更早版本
  • 几乎所有 DDL 都会锁表(包括改字段名、改长度、加索引等)

  • 拷贝期间:

    • 写操作完全阻塞

    • 读操作可能被阻塞(取决于存储引擎)

  • 大表 = 长时间不可用


2. MySQL 5.7
  • 引入了 In-Place DDL,部分操作可在线进行(如扩展 VARCHAR 长度、添加索引)

  • 但以下操作仍会重建表并锁写:

    • 修改字段名(CHANGE COLUMN

    • 缩小字段长度(如 VARCHAR(100) → VARCHAR(50)

    • 改变数据类型(如 INT → BIGINTCHAR → VARCHAR

    • 修改字符集或排序规则

-- 显式要求 Online DDL,utf8mb4 字符集63是分界线要注意,不可用的时候有提示不影响数据库使用,建议使用pt-osc
ALTER TABLE users
MODIFY COLUMN email VARCHAR(63) NOT NULL,
ALGORITHM = INPLACE,
LOCK = NONE;
3. MySQL 8.0.4+(重大改进)
  • 引入 Instant DDL,以下操作毫秒级完成,不触碰数据:

    • 添加/删除列(末尾)

    • 重命名列(RENAME COLUMN

    • 修改列默认值

  • 但以下操作仍需重建表:

    • 改变数据类型(如 INT → VARCHAR

    • 缩小字段长度

    • 在非末尾位置加列

安全方案:pt-online-schema-change 原理

  1. 创建影子表 _原表名_new,并应用新结构(含新字段名/类型/长度)

  2. 分批拷贝历史数据(按主键分块,避免高 I/O)

  3. 通过触发器同步增量变更(INSERT/UPDATE/DELETE 自动同步到新表)

  4. 原子切换:RENAME TABLE 瞬间完成,业务无感

  5. 自动清理中间对象

二、实用操作步骤

步骤 1:确认前提

-- 检查 MySQL 版本
SELECT VERSION();

-- 检查表结构和主键
SHOW CREATE TABLE your_table;

步骤 2:备份

mysqldump -h your_host -u backup_user -p 
  --single-transaction your_db your_table > backup_$(date +%Y%m%d).sql

步骤 3:安装工具(如未安装)

www.percona.com/downloads

# Mac
brew install percona-toolkit

步骤 4:构造 ALTER 语句(关键!)

场景示例:

原字段目标字段ALTER 语句
type VARCHAR(50)resource_type VARCHAR(100) NOT NULLCHANGE COLUMN type resource_type VARCHAR(100) NOT NULL
status TINYINTorder_status INT DEFAULT 0CHANGE COLUMN status order_status INT DEFAULT 0
name CHAR(20)full_name VARCHAR(50) NOT NULLCHANGE COLUMN name full_name VARCHAR(50) NOT NULL
  • CHANGE COLUMN 同时支持改名 + 改类型

  • 必须写出完整的新定义(类型、长度、是否为空、默认值)

步骤 5:执行变更(核心命令)

pt-online-schema-change 
  --host=your_db_host 
  --user=dba_user 
  --password='your_password' 
  --alter "CHANGE COLUMN old_col new_col VARCHAR(100) NOT NULL DEFAULT ''" 
  D=your_db,t=your_table 
  --execute 
  --max-load="Threads_running=25" 
  --critical-load="Threads_running=50" 
  --chunk-size=1000 
  --sleep=0.1 
  --progress=time,30
  • --max-load:负载高时暂停(防雪崩)

  • --chunk-size:每次拷贝 1000 行(根据 I/O 调整)

  • --sleep:每批间隔 0.1 秒(降低压力)

  • --progress:每 30 秒输出进度

--alter 参数只需要写 ALTER TABLE 之后的部分,不能包含 ALTER TABLE 表名

步骤 6:验证结果

-- 检查结构
SHOW CREATE TABLE your_table;

-- 抽样查询(验证数据和默认值)
SELECT id, new_col FROM your_table WHERE id IN (1, 100000, 1000000);

-- 检查空值(如改为 NOT NULL)
SELECT COUNT(*) FROM your_table WHERE new_col IS NULL;
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com