判断表是否该拆分,核心看数据更新频率和访问模式是否割裂:如用户基本信息与登录日志混存会导致锁表、查询变慢、备份增大;同一事务频繁修改字段应与只读字段分离;select * 常用但实际仅用少量列且含大字段(text/json)时应拆以避免i/o浪费;需权衡外键约束成本,join性能取决于关联字段索引与数据量;避免为理论规范硬拆低频小枚举值表;外键用于防应用bug致数据错乱,但会增加插入/更新开销及锁风险;高频写入表慎用级联删除;分库分表下外键基本失效;时间字段选timestamp适合跨时区事件时间,datetime适合固定预定时间;索引过多拖慢写入,单表超5–7个需警惕冗余索引;全文搜索勿依赖like '%xxx%',应使用fulltext或外部引擎;缓存命中率低于95%说明内存或索引设计不足;关键细节如未索引的order by或过长varchar主键常成性能瓶颈。

怎么判断一个表该不该拆成两个
核心看数据更新频率和访问模式是否割裂。比如用户基本信息(姓名、头像)和登录日志(IP、时间戳)混在一张表里,每次登录都要更新整行,会锁表、拖慢查询,还让备份变大。
实操建议:
- 同一事务里频繁修改的字段,尽量和只读字段分开
- 如果
SELECT *常用但实际只用其中 3 列,而另外 7 列又很大(比如TEXT或JSON),就该拆——避免 I/O 浪费 - 注意外键约束成本:拆表后加
JOIN是快是慢,得看关联字段有没有索引、数据量级是否过万 - 别为“理论上规范”硬拆——比如把
status单独建order_status表,但只有 3 个值且从不增删,纯属增加复杂度
外键到底要不要加
加外键不是为了“看起来规范”,而是防止应用层 bug 导致数据错乱。但代价明确:插入/更新时要校验、级联操作可能锁表、某些 ORM 或迁移工具会绕过它。
实操建议:
- 业务关键链路必须加,比如
order.user_id必须引用user.id,否则删了用户订单变孤儿 - 高频写入表慎用级联删除(
ON DELETE CASCADE),容易触发长事务或锁等待 - 分库分表场景下外键基本失效,得靠应用层或中间件保证一致性
- MySQL 8.0+ 支持延迟外键检查(
SET FOREIGN_KEY_CHECKS = 0),但只该用于导入/修复,不能常态关闭
时间字段用 DATETIME 还是 TIMESTAMP
本质区别不在精度,而在时区处理和取值范围。TIMESTAMP 存的是 UTC 时间戳,读写自动转本地时区;DATETIME 就是原样存字符串,不带时区信息。
开发语言:java,支持数据库:Mysql 5,系统架构:J2EE,操作系统:linux/Windows1. 引言 32. 系统的结构 32.1 系统概述 33. 功能模块设计说明 43.1 商品管理 43.1.1 添加商品功能模块 53.1.2 商品列表功能模块 83.1.3 商品关联功能模块 93.
实操建议:
- 记录“事件发生时间”(如支付完成时间),用
TIMESTAMP——跨时区服务能统一比对 - 记录“预定时间”(如会议开始时间),用
DATETIME——它本就不该随服务器时区漂移 -
TIMESTAMP只支持 1970–2038 年,金融或档案类系统必须用DATETIME - MySQL 5.6.4+ 两者都支持毫秒精度(
DATETIME(3)/TIMESTAMP(3)),别信老教程说TIMESTAMP不支持
索引太多反而拖慢写入,怎么平衡
每多一个索引,INSERT/UPDATE/DELETE 就得多维护一份 B+ 树。尤其在高并发写入场景,索引数量和大小直接决定吞吐瓶颈。
实操建议:
- 单表索引数超过 5–7 个就得警惕,先看
SHOW INDEX FROM table_name,删掉Cardinality极低或长期没被EXPLAIN用到的 - 复合索引别堆字段,
(a, b, c)能覆盖WHERE a=1 AND b=2,但对WHERE b=2无效——别指望“包含就一定可用” - 全文搜索别硬扛在
LIKE '%xxx%'上,真要模糊查就上FULLTEXT索引或外部引擎(如 Elasticsearch) - 监控
innodb_buffer_pool_reads和innodb_buffer_pool_read_requests比值,如果缓存命中率低于 95%,说明索引或数据太大,内存扛不住
设计不是画完 ER 图就结束,真正卡住的往往是某个没加索引的 ORDER BY created_at LIMIT 20,或者一个被当成主键用的 VARCHAR(255) 字段。细节不抠,模型再漂亮也跑不起来。









