修改表结构 ALTER TABLE
本教程共 46 篇 · 第 13 篇 · 更新于 2026-07-30 · 约 14 分钟阅读
13. 修改表结构 ALTER TABLE
本节目标:学会用 ALTER TABLE 给表加列、删列、改列类型、改列名、改表名,理解 MODIFY 和 CHANGE 的区别,并知道大表改结构的风险,养成改表前备份的习惯。
需求永远在变。表建好了,后来发现要加个字段、改个类型、换个名字,怎么办?不可能把表删了重建(数据就没了)。这时就用 ALTER TABLE,它是表结构的”修改器”。
13.1 ALTER TABLE 能干什么
ALTER TABLE 是 DDL 里最常用的语句之一,能做这些事:
- 加列:
ADD COLUMN - 删列:
DROP COLUMN - 改列类型:
MODIFY COLUMN - 改列名和类型:
CHANGE COLUMN - 改列名:
RENAME COLUMN - 改表名:
RENAME TO或RENAME TABLE - 加/删约束、加/删索引、改字符集、改存储引擎……
这一节聚焦”列和表名”的修改,约束和索引后面有专门章节。
13.2 准备一张测试表
先建张简单的表,后面在它上面演练:
USE shop;
CREATE TABLE vendors (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
13.3 ADD COLUMN:加列
给表加一个新列:
ALTER TABLE vendors
ADD COLUMN phone VARCHAR(15);
执行后用 DESC 看一下:
DESC vendors;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
| phone | varchar(15) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
新列默认加到最后。
指定列的位置
用 FIRST 或 AFTER 控制新列的位置:
-- 加到最前面
ALTER TABLE vendors
ADD COLUMN code CHAR(5) FIRST;
-- 加到 name 列后面
ALTER TABLE vendors
ADD COLUMN email VARCHAR(100) AFTER name;
Note
COLUMN关键字可省略,ADD phone VARCHAR(15)和ADD COLUMN phone VARCHAR(15)等价。但写上COLUMN更清晰,推荐保留。
一次加多列
用多个 ADD 子句,逗号分隔:
ALTER TABLE vendors
ADD COLUMN address VARCHAR(200),
ADD COLUMN remark VARCHAR(100) DEFAULT '';
13.4 DROP COLUMN:删列
删掉一列,连数据一起没:
ALTER TABLE vendors
DROP COLUMN remark;
Warning删列是不可逆的,列里的数据也跟着没了。删之前确认:
- 这列真的不用了吗?
- 有没有视图、存储过程、应用代码依赖它?
- 重要数据先备份。
删了再后悔就来不及了。
如果表里只剩一列,DROP COLUMN 会报错—MySQL 不允许一张表没有列:
-- 只剩 id 一列时
ALTER TABLE vendors DROP COLUMN id;
-- ERROR 1090 (42000): You can't remove all columns with ALTER TABLE
一次删多列
ALTER TABLE vendors
DROP COLUMN phone,
DROP COLUMN email;
13.5 MODIFY COLUMN:改列类型
MODIFY 用来改列的类型或约束,但不动列名。
-- 把 name 从 VARCHAR(50) 改成 VARCHAR(100)
ALTER TABLE vendors
MODIFY COLUMN name VARCHAR(100) NOT NULL;
执行后再 DESC:
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| name | varchar(100) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
name 变成了 VARCHAR(100),而且变成 NOT NULL 了。
常见的 MODIFY 场景
-- 改长度
ALTER TABLE vendors MODIFY name VARCHAR(200);
-- 改类型
ALTER TABLE vendors MODIFY phone CHAR(11);
-- 加 NOT NULL 和默认值
ALTER TABLE vendors MODIFY name VARCHAR(100) NOT NULL DEFAULT '';
-- 改默认值(用 ALTER 子句)
ALTER TABLE vendors ALTER name SET DEFAULT 'unknown';
-- 删默认值
ALTER TABLE vendors ALTER name DROP DEFAULT;
Note
MODIFY改类型有风险。把大类型改成小类型(如VARCHAR(200)改VARCHAR(50)),如果已有数据超过新长度,会被截断或报错。把字符串改成数字这类跨类型修改更要小心,最好先备份。
13.6 CHANGE COLUMN:改列名(和类型)
CHANGE 既能改列名,也能同时改类型。语法和 MODIFY 不同:要写旧列名 + 新列名 + 类型。
-- 把 phone 列改名为 mobile,类型不变
ALTER TABLE vendors
CHANGE COLUMN phone mobile VARCHAR(15);
-- 改名同时改类型
ALTER TABLE vendors
CHANGE COLUMN mobile contact CHAR(11) NOT NULL;
CHANGE 后面跟着的是:旧名 新名 新类型。
MODIFY 和 CHANGE 的区别
这是新手最容易混淆的两个:
| 命令 | 能改列名吗 | 能改类型吗 | 语法 |
|---|---|---|---|
MODIFY | 不能 | 能 | MODIFY 列名 新类型 |
CHANGE | 能 | 能 | CHANGE 旧列名 新列名 新类型 |
简单记:只改类型用 MODIFY,要改名用 CHANGE。CHANGE 是 MODIFY 的超集,但写起来啰嗦,只改类型时优先用 MODIFY。
Tip
CHANGE改列名时,类型必须重新写一遍,哪怕不变。漏写类型会报语法错误。这是CHANGE容易写错的地方。
13.7 RENAME COLUMN:只改列名(8.0+)
从 MySQL 8.0 起,新增了 RENAME COLUMN,专门用来只改列名,不动类型,语法更简洁:
ALTER TABLE vendors
RENAME COLUMN phone TO mobile;
不用写类型,比 CHANGE 干净。但要注意:8.0 才支持,老版本没有这个语法。
Note三种改列方式总结:
- 改类型不改名 ->
MODIFY- 改名又改类型 ->
CHANGE- 只改名(8.0+)->
RENAME COLUMN
13.8 改存储引擎和字符集
ALTER TABLE 还能改整张表的属性。
改存储引擎
ALTER TABLE vendors ENGINE = MyISAM;
Warning改存储引擎会重建整张表,大表上非常慢,而且 InnoDB 转 MyISAM 会丢事务、外键等特性。除非必要,别改引擎,新表统一 InnoDB。
改字符集和排序规则
ALTER TABLE vendors
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
改的是表的默认字符集,已有列的字符集不会自动跟着变。要让列也变,得用 MODIFY 逐列转换:
ALTER TABLE vendors
MODIFY name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
13.9 改表名:RENAME TABLE
表名想改,有两种写法。
方式一:ALTER TABLE … RENAME TO
ALTER TABLE vendors
RENAME TO suppliers;
方式二:RENAME TABLE 语句
RENAME TABLE vendors TO suppliers;
RENAME TABLE 还能一次改多个表:
RENAME TABLE
vendors TO suppliers,
buyers TO customers;
Tip
RENAME TABLE改表名是原子操作(要么全成功要么全失败),而且很快,因为它只改数据字典里的名字,不动数据文件。比ALTER TABLE ... RENAME更适合批量改名。
改表名的注意事项
改名前要想清楚这几个影响:
- 视图、存储过程、外键:引用了旧表名的对象不会自动更新,改名后可能失效;
- 应用代码:SQL 里写死旧表名的地方都要改;
- 权限:旧表的权限不会自动迁移到新表名;
- 临时表:
RENAME TABLE不能改临时表,临时表要用ALTER TABLE ... RENAME TO。
Warning我之前踩过坑:把一张被外键引用的表改名了,结果外键约束指向了不存在的表,后续操作各种报错。改名前先用
SHOW CREATE TABLE看看有没有被引用,改完要同步更新依赖对象。
13.10 大表 ALTER 的风险与建议
这一节最后必须讲风险。ALTER TABLE 在大表上可能很慢、甚至锁表。
哪些操作贵
- 改列类型、改字符集:通常要重建整张表,大表上耗时很长;
- 加普通索引:要扫描全表建索引;
- 改存储引擎:整表重建。
哪些操作便宜(8.0+ 优化)
InnoDB 在 8.0 后对很多 DDL 做了即时(INSTANT)优化:
- 加列到末尾:8.0.12+ 支持 INSTANT,秒级完成;
- 删列:8.0.29+ 支持 INSTANT;
- 改列默认值:通常很快;
- 改表名:极快。
Note26.7 里 INSTANT DDL 覆盖更广,加列、删列、改默认值这类常见操作对大表也几乎无感。但改列类型、改字符集这种仍可能需要重建表,大表上要谨慎。
改表前的安全建议
- 先备份:
mysqldump导出表结构和数据,改坏了能恢复; - 低峰期操作:大表 ALTER 可能锁表,避开业务高峰;
- 先在测试库验证:确认 SQL 语法和效果,再上生产;
- 预估耗时:大表可以先在同样规模的测试库测一下耗时;
- 用工具:生产大表改结构,业界常用
pt-online-schema-change、gh-ost这类在线改表工具,避免长时间锁表。
13.11 一个完整的改表示例
把这一节的操作串起来,演示一次完整的表结构演进:
-- 原表
CREATE TABLE vendors (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
-- 1. 加列
ALTER TABLE vendors
ADD COLUMN phone VARCHAR(15),
ADD COLUMN email VARCHAR(100) AFTER name;
-- 2. 改类型
ALTER TABLE vendors
MODIFY name VARCHAR(100) NOT NULL DEFAULT '';
-- 3. 改列名(8.0+)
ALTER TABLE vendors
RENAME COLUMN phone TO mobile;
-- 4. 删列
ALTER TABLE vendors
DROP COLUMN email;
-- 5. 改表名
RENAME TABLE vendors TO suppliers;
-- 验证
DESC suppliers;
SHOW CREATE TABLE suppliers\G
13.12 小结
这一节掌握了 ALTER TABLE 的全部常用操作:
ADD COLUMN加列,FIRST/AFTER控制位置;DROP COLUMN删列,不可逆,删前备份;MODIFY改类型不改名;CHANGE改名又改类型(旧名 新名 类型);RENAME COLUMN(8.0+)只改名;RENAME TABLE改表名,原子操作,可批量;- 大表改类型/字符集要重建表,低峰操作、先备份、用在线工具。
下一节讲删除表、临时表和复制表,把表操作这块收尾。