应合理设计字段类型、范式化程度、主键及索引:varchar按需设定长度,枚举用tinyint/enum,时间用datetime/timestamp,金额用decimal;避免过度拆表join,高频字段可冗余;主键优选自增整型;复合索引遵循等值→范围→排序顺序。

字段类型选太大,磁盘和内存都吃亏
用 VARCHAR(255) 存手机号、用 TEXT 存状态码、甚至所有字符串都上 LONGTEXT——这类“图省事”的设计,会直接拖慢查询、增加缓冲池压力、放大复制延迟。
实操建议:
-
VARCHAR长度按业务最大值设,比如身份证号固定 18 位,就用VARCHAR(18),不是VARCHAR(255) - 枚举类字段(如订单状态)优先用
TINYINT UNSIGNED或ENUM(注意ENUM排序和字符集陷阱),别用VARCHAR(20) - 时间字段不用
VARCHAR存"2024-03-15 14:22:03",该用DATETIME或TIMESTAMP;后者自动时区转换但范围小(1970–2038),要留心 - 数值不为零且无小数,别用
FLOAT或DOUBLE存金额,DECIMAL(10,2)更安全;整型够用就别上BIGINT,尤其主键——它会让二级索引变大一倍
过度范式化导致 JOIN 变成性能黑洞
把用户姓名、邮箱、地址全拆到 user_profile 表,再加个 user_setting、user_stats……查个列表就要 5 张表 JOIN,哪怕都有索引,执行计划也容易走错,缓冲池命中率直线下降。
实操建议:
- 高频读取的字段(如用户昵称、头像 URL、最后登录时间)建议冗余在主表,用应用层或触发器保证一致性,别迷信“完全范式”
- 真正变动频繁又体积大的数据(如用户长文本简介、多图 JSON 列表)才单独建表,且加好覆盖索引
-
JOIN超过 3 张表时,先看执行计划里有没有Using temporary或Using filesort;有,基本就是范式过头了 - MySQL 8.0+ 支持函数索引,可以用
JSON_EXTRACT(profile, '$.city')建索引,减少反范式字段数量
没主键或主键设计不合理,索引和复制全乱套
用 UUID 或 MD5 当主键?或者干脆用 INT 但没设 UNSIGNED 和 AUTO_INCREMENT?这会导致聚簇索引碎片严重、插入变随机、从库延迟飙升。
实操建议:
- 主键必须是
INT UNSIGNED AUTO_INCREMENT或BIGINT UNSIGNED AUTO_INCREMENT,除非你明确需要分布式 ID 且已用shard-key控制写入局部性 - 禁用
UUID作主键:它无序,每次插入都在 B+ 树中间找位置,页分裂多,缓冲池利用率低;真要用,至少转成BINARY(16)并用UUID_TO_BIN()处理 - 联合主键慎用——除非天然业务唯一且查询总带全字段,否则极易引发
INSERT ... ON DUPLICATE KEY UPDATE锁冲突 - 没有显式主键时,InnoDB 会悄悄建隐藏的
ROW_ID,但它是全局递增、非事务安全的,可能引发主从不一致
索引字段顺序和 WHERE 条件对不上,等于白建
建了复合索引 (status, created_at, user_id),但查询只写 WHERE user_id = ?,这个索引根本用不上。更糟的是,如果还顺手加了 ORDER BY created_at DESC,优化器可能放弃索引而走文件排序。
实操建议:
- 复合索引字段顺序按“等值查询字段 → 最左前缀可下推的范围字段 → 排序字段”排;比如常用
WHERE status = ? AND created_at > ? ORDER BY user_id,索引就该是(status, created_at, user_id) - 避免在索引字段上用函数或计算:
WHERE YEAR(created_at) = 2024无法走索引,改用created_at BETWEEN '2024-01-01' AND '2024-12-31' - 区分
SELECT *和SELECT id, name:后者若能被索引完全覆盖(即Extra显示Using index),就不用回表,速度差一倍以上 - 用
EXPLAIN FORMAT=TREE(MySQL 8.0+)看执行树,比老式EXPLAIN更清楚是否用了索引下推(Using index condition)
字段类型和范式不是教科书里的静态规则,而是得跟着查询模式、更新频率、数据量级一起调的参数。一个 TINYINT 和 SMALLINT 看似只差 1 字节,百万行就差 125KB;一次多余的 JOIN 在高并发下可能让 QPS 掉一半——这些细节不压到 explain 和 slow log 里,光看 DDL 是看不出问题的。











