讲解

DDL(Data Definition Language)是定义表结构的一类语句:CREATE TABLE 建表、ALTER TABLE 改结构、DROP TABLE 删表、RENAME 改名、TRUNCATE 清空。一张「生产级」的 CREATE TABLE 语句不止列定义,通常还包含存储引擎、字符集、表注释和列注释——注释不是摆设,半年后没人记得 status 列的每个值什么意思,COMMENT 就是写在结构里的文档。

ALTER TABLE 是日常变更的主力:ADD COLUMN 加列(可指定 AFTER 某列)、MODIFY COLUMN 改类型、DROP COLUMN 删列、ADD INDEX 加索引。MySQL 8.0 对「加列」这类操作支持 INSTANT 算法,几乎瞬间完成;但改列类型、删列仍可能需要重建整张表,大表上执行要慎重——百万行以上的表做结构变更,生产环境通常用 gh-ost 或 pt-online-schema-change 这类在线改表工具,避免长时间锁表。

两个要紧的语法细节:一是 DDL 会隐式提交——事务里执行 CREATE/ALTER 会把之前未提交的修改一并提交,DDL 本身也不能回滚;二是 IF EXISTS / IF NOT EXISTS 子句能让脚本可重复执行而不报错,写迁移脚本时应养成习惯。DROP TABLE 和 DROP DATABASE 一样没有回收站,生产环境的删除操作建议先 RENAME 成 xxx_tobedrop 观察几天,确认无引用再真删。

示例

一张要素齐全的建表语句:主键、注释、默认值、自动更新时间、普通索引,末尾指定引擎与字符集:

CREATE TABLE articles (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(200) NOT NULL COMMENT '文章标题',
  body TEXT COMMENT '正文',
  status VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT 'draft/published/archived',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';

用 ALTER TABLE 演进结构:加列、改列宽、补索引,然后看完整的表定义:

ALTER TABLE articles ADD COLUMN view_count INT NOT NULL DEFAULT 0 COMMENT '阅读量' AFTER status;

ALTER TABLE articles MODIFY COLUMN title VARCHAR(300) NOT NULL COMMENT '文章标题';

ALTER TABLE articles ADD INDEX idx_created (created_at);

SHOW CREATE TABLE articles;

改名再删除(生产上的安全姿势是先改名观察,这里合并演示),IF EXISTS 让脚本可重复执行:

ALTER TABLE articles RENAME TO posts;

SHOW TABLES;

DROP TABLE IF EXISTS posts;

SHOW TABLES;

常见坑

  • 以为 DDL 能回滚:DDL 隐式提交且自身不可回滚,事务保护不了 DROP TABLE。结构变更的正确兜底是变更前的备份。
  • 大表直接 ALTER:改列类型要重建整张表,千万行的表可能锁几十分钟,业务直接被打挂。大表变更用在线改表工具,并在低峰期执行。
  • MODIFY 时把注释和默认值弄丢:MODIFY COLUMN 是完整重新定义该列,漏写 DEFAULT 或 COMMENT 就会丢失原定义。执行前先 SHOW CREATE TABLE 抄全。
  • 改小列长度截断数据:VARCHAR(200) 改成 VARCHAR(50),超长数据在严格 SQL 模式下报错、非严格模式下被静默截断。收窄前先 SELECT MAX(CHAR_LENGTH(...)) 确认。

小结

CREATE TABLE 要写全引擎、字符集与注释;ALTER 负责演进结构,8.0 的 INSTANT 加列很快但重建型操作要防锁表;DDL 不可回滚,IF EXISTS 让脚本可重入。下一章看看表底下干活的存储引擎。