1027 字
约 3 分钟
6
S11-B02 · 建表:数据类型、字符集与范式
2024-12-31
2026-11-07

适用读者:设计表时凭感觉选类型的人。
前置:S11-B01。
实测环境:MySQL 8.0.46(s11lab,2026-11-05)。
覆盖旧文:1213(77) 1214(64) 2597(446) 1727(87) 2595(569) 1728(107) 837(83) 2596(398) 856(83) 1726(82) = 1,996 点。
覆盖扩展:E-S11-003(char/varchar)、E-S11-011(字符集与排序规则)。
上一篇:S11-B01 · 一条 SQL 怎么被执行:连接、解析、优化、执行
下一篇:S11-B03 · 查询。


1. 一句话结论

选类型的核心只有三条:占多少空间、能不能精确比较、会不会隐式转换。字符集选错,索引和比较规则都会跟着错。


2. 实测:char(64) 与 varchar(64) 的元数据

create table c1(c char(64), v varchar(64)) engine=InnoDB;
select column_name, character_maximum_length, character_octet_length
  from information_schema.columns where table_schema='s11lab' and table_name='c1';

实测输出:

COLUMN_NAME  CHARACTER_MAXIMUM_LENGTH  CHARACTER_OCTET_LENGTH
c            64                        256
v            64                        256

256 = 64 × 4 —— utf8mb4 每个字符最多 4 字节。

类型 存储 尾部空格 适用
char(n) 定长(不足补空格) 取出时去掉尾部空格(MySQL 行为,待核细节随版本) 长度固定的短串(性别、状态码)
varchar(n) 变长(长度前缀 + 内容) 保留 绝大多数字符串

判据:"这个字段的长度会变吗?" 会 → varchar;固定且极短 → char。


3. 字符集与比较规则(E-S11-011)

项 建议
字符集 utf8mb4(不是 utf8——后者只支持 3 字节,存不了 emoji)
排序规则 utf8mb4_0900_ai_ci(MySQL 8 默认,大小写不敏感)
大小写敏感 用 _bin 或 _as_cs
连接字符集 与表一致,否则隐式转换

"为什么 utf8 存不进 emoji" 是高频问题:MySQL 的 utf8 = utf8mb3(最多 3 字节),emoji 需要 4 字节 → 报错或被截断。

字符集不一致的后果:JOIN 时隐式转换导致索引失效(J02 的失效原因之一)。


4. 数据类型速查

类别 类型 注意
整数 tinyint/smallint/int/bigint 够用就好;int(11) 的 11 只是显示宽度(8.0 已废弃)
小数 decimal(p,s) 金额必须用 decimal(float/double 有精度误差,S09 实测过)
字符串 char/varchar/text text 不能有默认值、不利索引
时间 datetime/timestamp timestamp 受时区影响、范围小
布尔 tinyint(1) MySQL 没有真正的 boolean
JSON json 可索引需生成列

"金额用 float"是最经典的错误——0.1+0.2 != 0.3 在浮点下成立(S09-B02 有实测)。


5. 范式与反范式(A-856)

范式 要求 违反的后果
1NF 字段原子 一个字段存多个值 → 无法索引
2NF 非主键完全依赖主键 部分依赖 → 更新异常
3NF 非主键不依赖其他非主键 传递依赖 → 冗余不一致

反范式化的判据:"这个冗余能显著减少 JOIN 吗?且更新频率低吗?" 都满足 → 可冗余(如把用户昵称冗余到订单表)。


6. 五个误区

误区 真相
"utf8 就是 utf8mb4" utf8 只支持 3 字节
"varchar(64) 一定占 64 字符空间" 变长存储
"char 更快所以都用 char" 长度不固定会浪费空间
"金额用 double 没问题" 精度误差
"范式越高越好" 读多写少场景常需反范式

7. 自检

  1. char(64) 与 varchar(64) 在元数据上有什么相同/不同?
  2. 256 这个数字怎么来的?
  3. 为什么 utf8 存不了 emoji?
  4. 金额为什么必须用 decimal?
  5. 什么时候该反范式化?

8. 下一篇

S11-B03 · 查询:WHERE/JOIN/GROUP BY/子查询/分页

建表讲完,下一篇讲查询——重点是"书写顺序不等于执行顺序"这一条。


本篇属于系列《S11 · 数据库与 SQL》。旧文来源:A-1213/1214/2597/1727/2595/1728/837/2596/856/1726;扩展点 E-S11-003/011。元数据为 MySQL 8.0.46 实测。

S11-B02 · 建表:数据类型、字符集与范式
https://www.clxhxhhr.top/posts/5326/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。