优先用VARCHAR而非TEXT,慎用外键,区分TIMESTAMP与DATETIME场景,复合索引需覆盖查询路径——类型、约束、时间、索引四类设计须按实际读写特征权衡,否则隐患随流量放大。
TEXT 当万能字符串类型用很多工程师一遇到“字段可能很长”就直接上 TEXT,尤其在 MySQL 中。但 TEXT 类型不支持默认值、不能建普通索引(只能前缀索引)、无法参与内存临时表排序(ORDER BY 或 GROUP BY 时容易触发磁盘临时表),性能隐患明显。
实操建议:
VARCHAR(255) 或 VARCHAR(1024) —— 大多数业务场景(如标题、摘要、URL)完全够用,且支持索引和默认值TEXT,并明确加注释说明用途TEXT + LIKE,应搭配 FULLTEXT 索引或外部搜索引擎
外键看起来很安全,但实际在线上高并发写入场景中,它会成为锁竞争热点。比如订单表 order 关联用户表 user 的 user_id,每次插入订单都要校验 user 表主键是否存在 —— 这个校验会持读锁,可能阻塞用户信息更新。
更麻烦的是,跨库、分库、读写分离后,外键根本不可用。很多团队后期不得不删掉所有外键,靠应用层兜底。
实操建议:
NOT NULL + CHECK 约束替代部分业务规则(如状态值限定),比外键轻量且可控DATETIME 不区分场景DATETIME 和 TIMESTAMP 在 MySQL 中行为差异极大:TIMESTAMP 自动转时区、范围小(1970–2038)、占 4 字节;DATETIME 无时区转换、范围大(1000–9999)、占 8 字节。但很多人图省事,一律用 DATETIME,结果埋下两个坑:一是日志类时间(如 created_at)本该统一 UTC,却因时区不一致导致排查困难;二是存储空间翻倍,对亿级表的 I/O 和备份影响不小。
实操建议:
created_at / updated_at 用 TIMESTAMP(配合 DEFAULT CURRENT_TIMESTAMP),确保写入即固化为 UTCDATETIME,并额外存 timezone_offset 字段WHERE DATE(created_at) = '2025-01-01' 会导致索引失效WHERE 条件索引不是光让 WHERE 快就行。如果 SELECT 列太多、ORDER BY 字段没覆盖、或者 JOIN 条件没走索引,照样慢。典型例子:查询“最近 10 条订单”,写成 SELECT * FROM order WHERE user_id = ? ORDER BY created_at DESC LIMIT 10,但只给 user_id 建了单列索引 —— 数据库得先扫出所有该用户的订单,再内存排序,效率极低。
实操建议:
(user_id, created_at) 可支撑上面那个查询EXPLAIN 看 key_len 和 Extra(尤其是 Using filesort 或 Using temporary)来验证索引是否生效架构
