ER 图怎么画:实体、关系与基数标注
ER 图最实际的用途,是在动手写表结构之前把关系理清楚。等表建好再发现「一个订单可以有多个收货地址」这类需求,改起来就不是改图,而是改数据。花半小时画图,省的是后面几周的迁移成本。
实体怎么切:一个实体一张表
实体是「需要独立存在、有自己的标识、会被单独查询的东西」:用户、订单、商品、收货地址。判断方法是有没有独立的生命周期——订单能单独创建和查询,所以是实体;而订单里的「支付状态」不是实体,它是订单的一个属性。
- 实体名用单数名词,与将来的表名保持对应关系
- 每个实体必须能指出主标识,通常是自增 ID 或业务编号
- 属性只画关键字段,不要把每个字段都列出来,否则图会失控
- 需要独立查询、独立更新的「属性」,通常是漏掉的实体
关系与基数:把「一个」和「多个」写清楚
基数描述的是数量关系:一对一、一对多、多对多。这三类里,多对多是必须处理的——关系型数据库无法直接表达多对多,一定要引入中间表。图上不标清楚,实现时就会有人图省事把多个值塞进一个字段。
- 一对多:多的那一端加外键,连线在多的那端标「N」
- 多对多:拆出中间实体,两端各连一对多
- 一对一:通常是可拆可不拆的字段,拆开往往是因为字段太多或权限不同
- 可选与必填要标出,它决定外键能不能为 NULL
三类常见设计缺陷
看别人的 ER 图时,先找这三个问题,命中率很高。它们都是「图上看不出来,上线后才发现」的类型,所以在评审阶段抓出来最划算。
- 冗余存储:同一份数据在两个实体里各存一次,更新时必然不同步,应该只留一处
- 缺少中间表:多对多直接连,导致无法表达额外的关系属性(比如加入时间、角色)
- 实体过粗:把本该独立的对象塞成字段,等到需要单独查询或统计时就只能改表
画法:框、线、标注
标准的画法是实体用矩形,字段列在框内,主键加下划线或标记;关系用连线,两端标注基数。工具里没有专门的 ER 模板时,用矩形加连接线完全够用,关键是标注清楚,而不是追求符号规范。
- 实体框内分行写字段,主键置顶并标记
- 关系线用直线,两端写基数(1、N 或具体的数字范围)
- 关系本身带属性时,在连线上加一个小框表示关系属性
- 布局尽量让关系线短且不交叉,必要时把高频关联的实体放在一起
从 ER 图到建表
ER 图转建表基本是机械的:每个实体一张表,一对多的外键放在多的那端,多对多建中间表并加联合唯一索引。能机械转换是好事,说明图设计得足够清晰;如果需要大量临场发挥,通常说明图还没画完。
- 中间表建议加联合唯一约束,防止重复关系
- 常用查询路径上的字段考虑加索引,并在图上标注出来
- 删除策略要明确:是级联删除还是保留历史,这直接影响外键定义
- 图完成后与实际表结构做一次核对,避免图与实现长期不一致
常见问题
- ER 图和数据库表结构是什么关系?
- ER 图是设计阶段的抽象表达,表结构是实现结果,通常一一对应但不是必须。ER 图只画关键字段和关系,表结构包含全部字段、索引和约束。建议在 ER 图上标注与表名一致的实体名,方便对照。
- 多对多关系一定要建中间表吗?
- 在关系型数据库里,是的。直接在一个字段里存多个 ID 会导致无法建立外键约束、无法高效按关系查询、也无法记录关系自身的属性(如创建时间、角色)。引入中间表是最省事且最容易扩展的做法。
- ER 图需要画到字段类型吗?
- 评审设计时通常不需要,写明字段名和是否主键即可。等进入实施阶段,再单独做一份字段类型和索引的说明,把两类信息分开可以让设计评审更快。
- 字段很多的宽表怎么处理?
- 先判断这些字段是否都有相同的生命周期和访问频率。如果一部分字段很少访问,或者有独立的更新频率,就可以拆成一对一的关联表。拆分的依据是访问模式,而不是字段数量本身。