MySQL表操作硬核解析:从 CREATE TABLE 到磁盘文件、ALTER TABLE 与 DDL 风险

上篇文章:MySQL库操作硬核解析:字符集、校验规则、大小写比较、备份恢复与连接排查

目录

前言

创建表的基本语法

表的字符集、校验规则和继承关系

不同存储引擎对应不同磁盘文件

[查看表结构:DESC 与 SHOW CREATE TABLE](#查看表结构:DESC 与 SHOW CREATE TABLE)

插入数据:结构定义后的内容写入

[修改表结构:ALTER TABLE 是 DDL 的核心](#修改表结构:ALTER TABLE 是 DDL 的核心)

[添加字段:ADD COLUMN](#添加字段:ADD COLUMN)

修改字段类型:MODIFY

[删除字段:DROP COLUMN 的不可逆风险](#删除字段:DROP COLUMN 的不可逆风险)

[修改表名:RENAME TO](#修改表名:RENAME TO)

修改字段名:CHANGE

[删除表:DROP TABLE](#删除表:DROP TABLE)

表操作背后的磁盘变化

[MyISAM 与 InnoDB 的表文件差异](#MyISAM 与 InnoDB 的表文件差异)

表结构设计中的工程建议

[小结:表操作不是背 SQL,而是在修改数据结构和磁盘布局](#小结:表操作不是背 SQL,而是在修改数据结构和磁盘布局)


前言

表是业务实体的结构化表达。

在 MySQL 中,表是保存业务实体数据的核心结构。用户、订单、商品、文章、评论,都可以被抽象成表。表由字段组成,每个字段都有自己的名字、类型、默认值、字符集、校验规则、注释等属性。

如果说数据库是业务模块的数据边界,那么表就是业务实体的数据模型。设计表,本质上是在设计程序如何理解和组织数据。

创建表的基本语法

创建表语法如下:

sql 复制代码
CREATE TABLE table_name (
    field1 datatype,
    field2 datatype,
    field3 datatype
) CHARACTER SET 字符集 COLLATE 校验规则 ENGINE 存储引擎;

其中 field 表示列名,datatype 表示列类型。CHARACTER SET 指定表的字符集,如果没有指定,则默认使用所在数据库的字符集。COLLATE 指定表的校验规则,如果没有指定,则默认使用所在数据库的校验规则。ENGINE 指定存储引擎,如果没有指定,则使用 MySQL 默认存储引擎,现代版本通常是 InnoDB。

示例:

复制代码
mysql> create table if not exists user1(
    -> id int,
    -> name varchar(20) comment '用户名',
    -> password char(32) comment '用户的密码',
    -> birthday date comment '用户的生日'
    -> )character set utf8 collate utf8_general_ci engine MyIsam;
Query OK, 0 rows affected, 3 warnings (0.01 sec)

mysql> create table if not exists user2(
    -> id int,
    -> name varchar(20) comment '用户名',
    -> password char(32) comment '用户的密码',
    -> birthday date comment '用户的生日'
    -> )charset=utf8 collate=utf8_general_ci engine=InnoDB;
Query OK, 0 rows affected, 2 warnings (0.05 sec)

这个表包含四个字段:id、name、password、birthday。其中 name 使用 VARCHAR(20),表示可变长度字符串;password 使用 CHAR(32),适合保存固定长度的 MD5 字符串;birthday 使用 DATE,适合保存日期。

字段注释通过 COMMENT 添加,便于后续查看表结构时理解字段含义。

表的字符集、校验规则和继承关系

表可以指定自己的字符集和校验规则。如果没有指定,会继承所在数据库的默认设置。字段也可以单独指定字符集和校验规则,如果字段指定了,则字段优先级最高。

可以理解为:

字段级设置 > 表级设置 > 数据库级设置 > 服务器默认设置

这套继承关系非常重要。很多项目中出现"同一个库里不同表排序规则不一致""同一张表里字段字符集不同"的问题,根源就是建库、建表、建字段时没有统一规范。

工程建议是:建库时明确使用 utf8mb4,建表时除非特殊需求,否则保持继承,避免同一个系统内字符集混乱。

不同存储引擎对应不同磁盘文件

MySQL 表不是凭空存在的。创建表后,MySQL 会在数据目录下生成对应的文件。不同存储引擎生成的文件不同。

以 MyISAM 为例,早期版本中一个表通常对应三个文件:

users.frm:表结构

users.MYD:表数据

users.MYI:表索引

MySQL 8 环境里,创建 MyISAM 表后可以看到类似文件:

复制代码
# ll
total 128
drwxr-x---  2 mysql mysql   4096 Jun  6 21:19 ./
drwx------ 10 mysql mysql   4096 Jun  6 20:52 ../
-rw-r-----  1 mysql mysql   3991 Jun  6 21:11 user1_368.sdi
-rw-r-----  1 mysql mysql      0 Jun  6 21:11 user1.MYD
-rw-r-----  1 mysql mysql   1024 Jun  6 21:11 user1.MYI
-rw-r-----  1 mysql mysql 114688 Jun  6 21:19 user2.ibd

其中 .MYD 保存 MyISAM 数据,.MYI 保存 MyISAM 索引,.sdi 是 MySQL 8 中序列化的数据字典信息。InnoDB 表则常见:user2.ibd

.ibd 是 InnoDB 独立表空间文件,里面保存表的数据和索引页。笔记中同一个数据库下创建 MyISAM 和 InnoDB 表后,目录里出现:

user1_368.sdi

user1.MYD

user1.MYI

user2.ibd

这说明同样是 MySQL 表,不同存储引擎的物理组织方式不同。可以这样理解:

SQL 层看到的都是表

存储引擎层决定表如何落盘

文件系统层负责最终保存这些文件

这正是 MySQL 插件式存储引擎架构的体现。

查看表结构:DESC 与 SHOW CREATE TABLE

查看表结构:

DESC users;

DESC 适合快速查看字段结构,但它不是完整建表语句。想查看完整表定义,应使用:

SHOW CREATE TABLE users\G (\G 会把结果纵向展示,适合查看较长的建表语句。)

sql 复制代码
mysql> show create table user1 \G
*************************** 1. row ***************************
       Table: user1
Create Table: CREATE TABLE `user1` (
  `id` int DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` char(32) DEFAULT NULL COMMENT '用户的密码',
  `birthday` date DEFAULT NULL COMMENT '用户的生日'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
1 row in set (0.00 sec)

mysql> show tables;
+-------------------+
| Tables_in_user_db |
+-------------------+
| user1             |
| user2             |
+-------------------+
2 rows in set (0.00 sec)

mysql> alter table user1 rename to user;
Query OK, 0 rows affected (0.02 sec)

mysql> show tables;
+-------------------+
| Tables_in_user_db |
+-------------------+
| user              |
| user2             |
+-------------------+
2 rows in set (0.00 sec)

mysql> desc user;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int         | YES  |     | NULL    |       |
| name     | varchar(20) | YES  |     | NULL    |       |
| password | char(32)    | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

SHOW CREATE TABLE 能看到字段类型、默认值、注释、存储引擎、字符集等完整信息。排查线上表结构时,它比 DESC 更可靠。

插入数据:结构定义后的内容写入

创建表后可以插入数据:

sql 复制代码
mysql> desc user;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int         | YES  |     | NULL    |       |
| name     | varchar(20) | YES  |     | NULL    |       |
| password | char(32)    | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> insert into user values (1, '张三', '12344556', '2020-9-10');
Query OK, 1 row affected (0.00 sec)

mysql> insert into user values (2, '李四', '12386566', '2020-3-10');
Query OK, 1 row affected (0.01 sec)

mysql> select * from user;
+------+--------+----------+------------+
| id   | name   | password | birthday   |
+------+--------+----------+------------+
|    1 | 张三   | 12344556 | 2020-09-10 |
|    2 | 李四   | 12386566 | 2020-03-10 |
+------+--------+----------+------------+
2 rows in set (0.00 sec)

修改表结构:ALTER TABLE 是 DDL 的核心

实际项目中,表结构经常需要变化。例如增加字段、删除字段、修改字段类型、修改字段名、调整字符集、修改存储引擎、重命名表。这些操作都属于 DDL,常用 ALTER TABLE 完成。

常见语法包括:

sql 复制代码
ALTER TABLE tablename ADD column datatype [DEFAULT expr];
ALTER TABLE tablename MODIFY column datatype [DEFAULT expr];
ALTER TABLE tablename DROP column;
ALTER TABLE tablename CHANGE old_column new_column datatype;
ALTER TABLE tablename RENAME TO new_table_name;

DDL 操作往往比普通数据操作风险更高,因为它修改的是数据结构。尤其是大表执行 DDL,可能涉及重建表、复制数据、加元数据锁、阻塞读写等问题。学习阶段可以直接执行,生产环境必须谨慎。

添加字段:ADD COLUMN

给表添加字段,例如添加用户头像路径:

sql 复制代码
mysql> alter table user add image_path varchar(128) comment '用户头像路径' after birthday;
Query OK, 2 rows affected (0.04 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from user;
+------+--------+----------+------------+------------+
| id   | name   | password | birthday   | image_path |
+------+--------+----------+------------+------------+
|    1 | 张三   | 12344556 | 2020-09-10 | NULL       |
|    2 | 李四   | 12386566 | 2020-03-10 | NULL       |
+------+--------+----------+------------+------------+
2 rows in set (0.00 sec)

mysql> desc user;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | int          | YES  |     | NULL    |       |
| name       | varchar(20)  | YES  |     | NULL    |       |
| password   | char(32)     | YES  |     | NULL    |       |
| birthday   | date         | YES  |     | NULL    |       |
| image_path | varchar(128) | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> show create table user \G
*************************** 1. row ***************************
       Table: user
Create Table: CREATE TABLE `user` (
  `id` int DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` char(32) DEFAULT NULL COMMENT '用户的密码',
  `birthday` date DEFAULT NULL COMMENT '用户的生日',
  `image_path` varchar(128) DEFAULT NULL COMMENT '用户头像路径'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
1 row in set (0.00 sec)

可以看到,插入新字段后,原来的数据仍然存在。新字段对已有行默认填充 NULL,除非指定默认值。

AFTER birthday 表示把新字段放在 birthday 字段之后。如果不指定位置,通常默认添加到最后。

修改字段类型:MODIFY

修改字段类型,例如把 name 长度从 20 改成 60:

需要注意:MODIFY 修改字段定义时,如果原字段有注释、默认值、非空约束等,而新定义没有写,可能会导致这些属性丢失。因此修改字段时要完整考虑字段定义,而不是只写类型。

sql 复制代码
mysql> alter table user modify name varchar(60);
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> show create table user \G
*************************** 1. row ***************************
       Table: user
Create Table: CREATE TABLE `user` (
  `id` int DEFAULT NULL,
  `name` varchar(60) DEFAULT NULL,
  `password` char(32) DEFAULT NULL COMMENT '用户的密码',
  `birthday` date DEFAULT NULL COMMENT '用户的生日',
  `image_path` varchar(128) DEFAULT NULL COMMENT '用户头像路径'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
1 row in set (0.00 sec)

删除字段:DROP COLUMN 的不可逆风险

删除字段:

sql 复制代码
mysql> alter table user drop password;
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> desc user;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | int          | YES  |     | NULL    |       |
| name       | varchar(60)  | YES  |     | NULL    |       |
| birthday   | date         | YES  |     | NULL    |       |
| image_path | varchar(128) | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> select * from user;
+------+--------+------------+------------+
| id   | name   | birthday   | image_path |
+------+--------+------------+------------+
|    1 | 张三   | 2020-09-10 | NULL       |
|    2 | 李四   | 2020-03-10 | NULL       |
+------+--------+------------+------------+
2 rows in set (0.00 sec)

mysql> show create table user\G
*************************** 1. row ***************************
       Table: user
Create Table: CREATE TABLE `user` (
  `id` int DEFAULT NULL,
  `name` varchar(60) DEFAULT NULL,
  `birthday` date DEFAULT NULL COMMENT '用户的生日',
  `image_path` varchar(128) DEFAULT NULL COMMENT '用户头像路径'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
1 row in set (0.00 sec)

结果中不再有 password 字段。

更重要的是,删除字段不仅删除表结构中的列,还会删除该列对应的所有数据。原来的密码数据会消失。课件中特别提醒:删除字段一定要小心,删除字段及其对应列数据都没了。

生产环境中删除字段通常要经过几个阶段:先确认业务不再使用,代码停止读写该字段,保留一段观察期,再执行删除,并且删除前必须备份。

修改表名:RENAME TO

修改表名:

sql 复制代码
ALTER TABLE users RENAME TO employee;

其中 TO 可以省略:

sql 复制代码
ALTER TABLE users RENAME employee;

重命名表后,原表名不再可用。业务代码、SQL、权限、备份脚本中引用旧表名的地方都需要同步修改。

修改字段名:CHANGE

将 name 字段修改为 xingming:

sql 复制代码
mysql> desc user;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | int          | YES  |     | NULL    |       |
| name       | varchar(60)  | YES  |     | NULL    |       |
| birthday   | date         | YES  |     | NULL    |       |
| image_path | varchar(128) | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> alter table user change name xingming varchar(60) DEFAULT NULL;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc user;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | int          | YES  |     | NULL    |       |
| xingming   | varchar(60)  | YES  |     | NULL    |       |
| birthday   | date         | YES  |     | NULL    |       |
| image_path | varchar(128) | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

删除表:DROP TABLE

删除表语法:

sql 复制代码
DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ...

删除表会删除表结构和表数据。对于不同存储引擎,底层对应的数据文件也会被删除。例如 MyISAM 的 .MYD、.MYI,InnoDB 的 .ibd 等文件都会受到影响。

DROP TABLE 和 DROP DATABASE 一样,都是高危 DDL。执行前必须确认对象、环境和备份情况。尤其是生产环境中,误删表往往是严重事故。

表操作背后的磁盘变化

创建数据库和表后,可以在 Linux 数据目录中看到对应变化。创建数据库,本质上会创建目录:

bash 复制代码
/var/lib/mysql/user_db

创建 MyISAM 表,可能出现:

bash 复制代码
user1_368.sdi
user1.MYD
user1.MYI

创建 InnoDB 表,可能出现:

bash 复制代码
user2.ibd

执行 ALTER TABLE user1 RENAME TO user; 后,MySQL 内部表名改变,底层相关文件也会随之调整。执行 ALTER TABLE user ADD image_path ... 后,表结构改变,已有记录新字段默认变为 NULL。执行 ALTER TABLE user DROP password; 后,表结构和对应列数据都会消失。

从这个角度看,DDL 并不是"改一下元信息"那么简单。很多 DDL 可能需要重建表结构、迁移数据、更新数据字典、修改底层文件。表越大,DDL 成本越高,风险越大。

MyISAM 与 InnoDB 的表文件差异

MyISAM 表结构和数据、索引通常分开存放:

.MYD:数据

.MYI:索引

.sdi / .frm:表结构或数据字典信息

InnoDB 表常见 .ibd 文件,数据和索引都以页的形式组织在表空间文件中。InnoDB 的聚簇索引结构决定了数据和主键索引关系非常紧密。虽然这部分超出了当前 PDF 范围,但这里至少要建立一个概念:InnoDB 不是简单把每行数据顺序写入文件,而是通过页、B+Tree、redo log、undo log、buffer pool 等机制管理数据。

因此,选择存储引擎会直接影响表的物理组织方式、事务能力、锁粒度、崩溃恢复和性能表现。

表结构设计中的工程建议

表结构设计不是随便写几个字段。即使是基础阶段,也应该形成一些习惯。

字段名要表达业务含义,例如 name、birthday、image_path。字段类型要匹配数据特点,固定长度字符串可以用 CHAR,可变字符串用 VARCHAR,日期用 DATE。字段注释要写清楚,方便维护。字符集和校验规则要统一,避免同库不同表、同表不同字段混乱。删除字段和删除表前必须备份。修改字段时要注意完整定义,避免丢失注释、默认值等属性。

更重要的是,大表上的 DDL 要谨慎。开发环境里 ALTER TABLE 可能瞬间完成,生产环境里可能因为数据量大导致长时间锁表、阻塞业务、复制延迟甚至引发故障。

小结:表操作不是背 SQL,而是在修改数据结构和磁盘布局

表是 MySQL 管理数据的核心单位。CREATE TABLE 定义业务实体结构,DESC 和 SHOW CREATE TABLE 用于查看表结构,ALTER TABLE 用于修改字段、类型、表名和字段名,DROP TABLE 用于删除整张表。不同存储引擎会让表在磁盘上呈现不同文件形态,MyISAM 和 InnoDB 的物理组织方式明显不同。

真正掌握表操作,不能只会写命令,还要知道这些命令背后发生了什么:创建表可能生成数据文件,添加字段会影响已有记录的默认值,修改字段可能改变数据定义,删除字段会删除整列数据,删除表会清除结构和内容。MySQL 表操作的本质,是在 SQL 抽象层、存储引擎层和文件系统层之间建立映射。只有理解这个映射,才能写出安全、可维护、可恢复的数据库结构设计。

相关推荐
数据库小学妹1 小时前
PostgreSQL迁移到国产数据库怎么做?评估、改造、上线全流程实操指南
数据库·经验分享·postgresql·dba
Fanta丶1 小时前
19.Mysql覆盖索引、前缀索引
mysql
前端程序猿i1 小时前
Nginx 教程:从入门到能上线
运维·nginx
AskHarries1 小时前
权限模型:Shell、Browser、文件读写的安全边界
服务器·前端·网络
木雷坞1 小时前
Qdrant Docker 部署教程:数据卷、API Key 和集合初始化
运维·docker·容器·知识图谱
wuminyu1 小时前
Java锁机制之park和unpark源码剖析
java·linux·c语言·jvm·c++
周易宅1 小时前
Hermes Agent 内部/后端命令速查表
ai·agent·hermes
团象科技1 小时前
外贸站选海外服务器 拆解跨境运营中常被忽略的核心性能细节
运维·服务器
x***r1512 小时前
Redis Desktop Manager 0.8.8 安装教程(Windows redis-desktop-manager-0.8.8.384详细步骤)
数据库·windows·redis