ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ER图设计实战:概念建模、主键外键、范式与逆向工程

2026/9/17 18:24:52 拓冰建站 浏览量
ER图设计实战:概念建模、主键外键、范式与逆向工程 1. 为什么很多人画的第一版ER图都是废的我接手过一个跑了六年的业务系统数据库里 180 多张表字段注释覆盖率不到三成交接文档只有一份三年前的截图。新需求要做数据迁移第一步就是把 ER图重新画出来。那是我第一次真切感受到ER图这东西不是交作业用的它是数据库世界里少数能把业务语义和存储结构放在同一张纸上对齐的工具。绝大多数人画 ER图的方式是错的打开工具拖几个矩形看到字段就往上填看到外键就连一条线半小时一张图看起来很完整。问题是这张图不解决任何问题——它只是把建表语句翻译成图形没有回答这个字段为什么存在这条关系能不能是 1 对多业务上这个实体到底该不该独立。等到开发照着它建库业务一变整张图推倒重来。ER图真正的产出物是决策记录不是美术作品。它要回答的是哪些东西是实体实体之间是什么关系关系的基数是多少谁依赖谁。这些决策做完了建表几乎是机械劳动做错了后面所有 SQL、索引、增删改查的代码都建在流沙上。这篇内容我会按概念建模、主键表示、案例推演、逆向导出、工具选型、范式检查这几个角度把 ER图从画着玩拉到能交付。数据库课程设计、真实项目建模、老库重构三拨人都能拿去直接用。1.1 ER图的核心作用是统一语义不是画得好看同一个字段业务方叫客户编号开发叫cust_id财务叫户号测试叫用户ID。这些叫法在需求会上不会打架因为大家都默认说的是一回事。等到写 SQL 的时候一个JOIN条件写错数据就悄悄对不上了——而且不报错。ER图的第一个价值就在这儿给每个名词钉死一个唯一的名字和一份唯一的定义。图上一个实体叫客户那么它在需求文档、数据库表名、API 字段、前端展示里必须是同一个概念不能一会儿指自然人、一会儿指企业、一会儿又指联系人。这件事听起来像废话但我在项目里见过太多次客户表和用户表并存最后发现两张表存的是同一批人的不同切片。第二个价值是暴露结构缺陷。一张手画的 ER图铺在桌上1 对多和 多 对多一眼就能看出来。业务方说一个订单只能属于一个客户那就是 1:N说一个客户可以有多个收货地址一个地址也可能被多个客户共用那就是 M:N。这些结论写在图上是显性的藏在脑子里是隐性的后者迟早出事。第三个价值才是沟通。图是给非技术人员看的所以它不该出现varchar(64)、ON DELETE CASCADE这类物理细节。图上一旦开始出现类型和长度说明你已经把两层东西搅在一起了。1.2 概念、逻辑、物理三层混着画是返工的最大来源我在评审里看过最多的错误是一张图里既有椭圆属性又有bigint类型还有索引标注。这不是 ER图这是把三张图糊在一起。把三层分开事情会简单非常多层次关注点允许出现的元素不该出现的元素概念模型业务语义实体、属性、联系、基数类型、长度、索引、约束逻辑模型结构设计表、列、主外键、规范化存储引擎、分区、执行计划物理模型落地实现索引、分区、字符集、参数业务讨论、命名分歧概念层只回答有什么逻辑层回答怎么存物理层回答跑得快不快。概念层画错了逻辑层再怎么优化都是白费物理层纠结太久概念层没定做出来也是返工。我的习惯是概念图用白板或者最简单的图形工具只画矩形、菱形、连线和基数不碰工具的高级功能。逻辑图才进 PowerDesigner、DBX 这类建模工具让它自动生成 DDL。这样做的好处是概念讨论阶段没人会被工具绑架改起来就是擦掉重画三十秒的事。还有一个隐藏好处概念图可以拿给完全不懂数据库的人看。业务方看得懂学生选课看不懂student_course中间表。让业务方在概念图上签字比让他审 DDL 容易十倍。1.3 这几种场景下ER图确实可以省掉不是所有项目都值得画 ER图硬画反而是浪费。第一种只有三五张表的小工具。比如一个内部配置管理页面两张表存配置项和分组。这种场景你直接建表更快画图的时间比写 SQL 还长。判断标准很简单如果整个模型你能在脑子里同时装下并且不会记混就不需要图。第二种纯 KV 型或文档型存储。用 JSON 文档存整条业务记录、用键值对存会话这类场景天然没有强关系画 ER图反而是在硬套关系模型。向量数据库、缓存、日志存储基本都属于这一类。第三种临时表、中间表、ETL 落地表。这些表的生命周期由任务决定不是业务实体画进 ER图只会污染模型。但只要命中下面任意一条ER图就必须画表数量超过 20 张有多个团队并行开发业务方需要参与确认数据库要长期演进有合规或审计要求需要说明数据血缘。这几条任意一条成立不画图就是在给自己埋雷。2. 实体、属性、联系三个元素里藏着最多的判断分歧ER图就三个积木实体、属性、联系。工具书上一页就讲完了但真正卡人的从来不是怎么画而是这个名词到底算实体还是算属性。这个判断做错了整张图的形状就变了。2.1 划分实体的实操判据我判断一个名词是不是实体用三个问题按顺序问第一它有没有独立生命周期客户有——注册、变更、注销。订单有——创建、支付、完成、退款。而订单金额没有它依附于订单存在订单没了它也就没意义所以它是属性。第二它会不会被多处引用一个部门会被员工引用、被预算引用、被资产引用那它就是实体。一个订单备注只出现在订单里那就是属性。第三它有没有自己的属性地址这个词很典型。如果业务只需要一个字符串那它就是属性如果业务需要拆省市区、需要维护邮编和联系人那它就该独立成实体。这三条按顺序问大部分情况都能定下来。真正难的是边界案例比如课程和课程班次——同一个课程编号每学期开一次教师可能不同、教室可能不同。这时候要把课程教学大纲层面和开课班次具体一次授课拆成两个实体否则选课关系会挂错地方。这个坑我在教学管理系统里踩过下面第 4 节会详细说。2.2 属性粒度的取舍属性拆到多细取决于要不要按它查询和比较。手机号存成一个字段还是拆成国家码加号码如果业务要按国家码统计就拆不需要就存一个。身份证号要不要拆出生日期如果只是展示不拆如果要按年龄分层做运营拆出来单独存。多值属性是必须处理的。一个客户有多个联系电话你不能在客户表里开phone1、phone2、phone3那是典型的反模式加到第四个号码时就得改表结构。正确做法是把电话号码独立成实体或弱实体跟客户建立 1:N 关系。派生属性同理。账户余额可以从所有交易流水累加得到那它在概念模型里就是个派生属性用虚线椭圆标注不进物理表或者只在物理层做冗余快照。这个概念上的区分直接决定了后面要不要做对账逻辑。2.3 联系的基数、参与度与属性化处理基数就是 1:1、1:N、M:N这个大家都熟。真正容易漏的是参与度也就是这一端是不是必须存在。举个例子一个订单必须有客户这叫客户端的完全参与用双线表示一个客户可以没有任何订单这叫部分参与单线。参与度在概念图上看起来只是线条粗细但它对应到物理层就是NOT NULL还是允许空以及外键要不要加约束。另一个高频问题是联系上的属性。学生选修课程这个联系成绩挂在哪成绩不属于学生也不属于课程它属于这个学生选这门课这件事本身。所以成绩是联系的属性在 ER图上画成挂在菱形上的椭圆。等到落表的时候这个带属性的 M:N 联系会变成一张独立的关联表成绩就是那张表的列。什么时候该把联系升级成实体当这个联系需要被别的联系引用的时候。比如选课记录需要被成绩变更日志引用那选课就不能只是个菱形了它得变成一个实体关联实体。这个升级动作在概念图上就要完成不能留到建表的时候临时加表。3. 主键、弱实体与外键在ER图中的画法和表示ER图主键怎么表示是被问得最多的具体问题之一因为不同教材用的记号法不一样画出来长得完全不同考试和评审都容易吃亏。我按记号法分类说一遍。3.1 主键在四种主流记号法里的画法记号法实体画法主键表示外键表示常见于Chen 记号法矩形属性椭圆加下划线不画或另标教材、考试Crows Foot / IE带字段的矩形首行标 PK 或加下划线标 FK工程实践IDEF1X矩形分隔线以上标 PK标 FK带虚线传统企业建模UML 类图类框加{PK}或 stereotype关联线 多重度面向对象团队Chen 记号法是国内数据库课程设计最常用的主键属性椭圆画一条下划线。这里有个细节下划线只能有一条复合主键是把多个属性各自加下划线而不是给一个组合加线。弱实体的部分键用虚下划线或波浪下划线这个区分在判卷时经常是得分点。Crows Foot 就务实得多直接在一行字段后面标PK复合主键就标两行PK。它把字段名、类型、主键标记全塞进矩形里图更紧凑也更接近真实表结构。我推荐实际项目用这种因为它可以直接从图生成 DDL。3.2 复合主键与候选键的处理复合主键在关联表里几乎必然出现。选课表的(student_id, course_offering_id)、订单明细表的(order_id, line_no)都是典型的复合主键。这里有个取舍要不要加代理键。加一个自增id做主键业务上的复合唯一约束降级成UNIQUE——好处是外键引用简单、索引窄、后续改业务规则方便坏处是多一列、多一个索引、跨库同步时自增冲突。我的经验是业务表加代理键纯关联表不加直接用两列组合做主键。理由是关联表通常不会被别的表引用没必要多一层间接。候选键要标出来。身份证号、工号、订单号这类业务唯一标识图上应该标UNIQUE或者用虚线标候选键。不标的话后面做唯一约束时就会漏等到线上出现重复数据才想起来补那就要先清洗数据再加约束成本高十倍。3.3 弱实体与识别关系弱实体这个概念被很多人忽略了但它在真实建模里非常有用。判断标准是这个实体能不能脱离另一个实体独立存在。订单明细就是典型弱实体。单独的第 3 行没有意义必须依附订单。所以它是双线矩形它和订单之间的菱形也是双线识别联系它的主键是订单号 行号——订单号来自属主行号是它自己的部分键。在 Chen 记号法里弱实体的部分键用波浪下划线或者虚下划线在 Crows Foot 里标PK的同时把属主主键那几列也标上PK或FK。为什么要在概念层区分弱实体因为它决定了级联删除的语义。订单删除时明细必须跟着删这是识别关系自带的行为。如果你把它们当成两个强实体就得到处写清理逻辑迟早漏掉。3.4 外键要不要出现在概念ER图里这是个反复争论的问题。我的答案是概念图上不画外键逻辑图上必须画。概念图关心的是关系存不存在至于这个关系是靠哪一列实现的属于物理实现细节。在概念图上把外键标出来会让图变乱而且会误导——因为在 1:N 关系里外键放在哪一端是物理选择不是业务事实。但到了逻辑图外键必须显式因为它决定了JOIN怎么写、索引加在哪、删除时怎么处理。逻辑图上的外键是开发直接照着写代码的依据。中间那个过渡动作很关键从概念图到逻辑图1:N 关系要在 N 端加外键列M:N 关系要展开成独立关联表多值属性要展开成独立表。这三条映射规则记住了转化基本不会错。4. 两个案例的完整建模推演教学管理系统与银行储蓄系统概念性的东西讲完看两个具体案例。这两个是数据库课程设计里被选得最多的题目也是最容易画错的题目。4.1 教学管理系统ER图从需求清单到实体清单先别打开工具。第一步是把需求里的名词全部列出来不做任何判断学生、教师、课程、教材、院系、专业、班级、教室、学期、开课安排、选课记录、成绩、教学计划、课程类型、学分、学时。第二步按第 2.1 节的三条判据筛名词判断结论学生有生命周期被多处引用实体教师有生命周期被开课引用实体课程有独立大纲被教学计划引用实体开课安排每学期独立产生被选课引用实体院系被教师、专业、班级引用实体专业被班级引用有培养方案实体班级有生命周期被学生引用实体教室被排课引用可复用实体学期被开课引用实体或枚举属性选课记录有成绩等自身属性关联实体独立成表成绩附属于选课记录属性学分、学时附属于课程属性教材被开课引用有 ISBN 等属性实体关键的一步是把课程和开课安排分开。课程是教学大纲层面的抽象比如数据结构4 学分开课安排是具体一次的授课比如2024 秋数据结构张三老师周三 3-4 节A301。选课选的是开课安排不是课程本身。不拆开的话你没法处理同一门课上下两学期都开、老师不同这种情况。这个拆分是教学管理系统 ER图里最高频的错误。很多同学直接把选课关系画成学生 - 选修 - 课程等到要统计某学期某老师的学生人数时发现无路可走。4.2 选课关系的三元纠缠怎么解拆完实体之后选课关系变成学生、开课安排、还有学期。要不要把学期也放进联系里答案是学期已经在开课安排里了不需要重复。但如果你的系统允许重修同一个学生在同一门课课程层面上可能有多次选课记录那么学生 课程 学期才是唯一标识。这时候要不要引入学期作为三元联系的一部分我的处理办法是让唯一性约束落在学生 开课安排上因为开课安排本身就隐含了学期。这样既是二元关系又天然支持重修。只有在特殊场景下比如考试报名表需要单独记录学期才引入三元联系。三元联系在图上是个菱形连三条线。它的物理落地永远是一张独立表主键是三个参与实体主键的组合——或者在引入代理键之后用代理键做主键、三列做唯一约束。记住这条映射规则三元联系就不会画完不知道怎么落表。顺带说一个高频坑成绩。成绩属于某学生选了某开课安排这件事所以它是选课记录的属性。但如果有补考、重修、平时分和期末分成绩就变成多值了需要拆成成绩明细表。这个演进在很多课程设计里没有体现导致最后成绩只能存一个数字。4.3 银行储蓄系统ER图账户与交易的建模陷阱银行这个案例看着简单坑比教学系统还多。先列核心实体客户、账户、网点、柜员、交易流水、卡、产品存款类型。关系客户与账户是 1:N 吗不一定。联名账户的存在让它是 M:N。所以客户 - 持有 - 账户必须是带属性的多对多联系属性包括持卡角色主卡人/附属和生效日期。这一条是银行储蓄系统 ER图里最常被忽略的。账户与交易是 1:N交易流水是弱实体吗我倾向于当作强实体因为它有独立的交易流水号且可能被对账、清算、争议处理等多个模块引用。但它和账户之间的关系是依赖性的。交易流水的自反联系是另一个坑。转账会产生两条流水转出、转入这两条必须能被关联起来。做法是在交易流水上加一个关联流水号或者转账批次号形成自反关系。图上表现为一个环形连线。不处理这个的话对账时根本没法把一笔转账的两条腿配起来。还有一个必须做对的判断余额是派生属性。它等于初始金额加上所有流水的净额。概念图上应该标成派生虚线物理层才考虑做冗余字段加定时对账。把余额当成普通属性直接存却不在图上说明它是冗余的后面接手的人会以为它是权威数据源然后在对账时崩溃。4.4 从ER图落到建表语句的映射规则从图到 DDL是七条机械规则记熟之后不需要思考每个强实体 → 一张表实体主键 → 表主键。每个弱实体 → 一张表主键 属主主键 部分键。1:1 联系 → 外键放在参与度完全的那一端加唯一约束。1:N 联系 → N 端加外键指向 1 端主键。M:N 联系 → 独立建表主键为两端主键组合。多值属性 → 独立建表主键为属主主键 值列。带属性的联系 → 属性作为关联表的列。举个最小例子学生选课CREATE TABLE student ( student_id BIGINT PRIMARY KEY, name VARCHAR(32) NOT NULL, major_id BIGINT, CONSTRAINT fk_student_major FOREIGN KEY (major_id) REFERENCES major(major_id) ); CREATE TABLE course_offering ( offering_id BIGINT PRIMARY KEY, course_id BIGINT NOT NULL, teacher_id BIGINT NOT NULL, term VARCHAR(16) NOT NULL, CONSTRAINT fk_offering_course FOREIGN KEY (course_id) REFERENCES course(course_id), CONSTRAINT fk_offering_teacher FOREIGN KEY (teacher_id) REFERENCES teacher(teacher_id) ); CREATE TABLE enrollment ( student_id BIGINT NOT NULL, offering_id BIGINT NOT NULL, score DECIMAL(5,2), enrolled_at DATETIME NOT NULL, PRIMARY KEY (student_id, offering_id), CONSTRAINT fk_enroll_student FOREIGN KEY (student_id) REFERENCES student(student_id), CONSTRAINT fk_enroll_offering FOREIGN KEY (offering_id) REFERENCES course_offering(offering_id) );enrollment就是规则 5 和规则 7 的合并结果M:N 联系展开成表联系的属性score变成列。这张表的主键是复合的没加代理键因为它不被别的表引用。5. 没有文档的老库反向导出ER关系图的完整路径真实工作里更常见的不是从零画图而是从已有的库倒推。库里的表就是事实来源但事实来源往往是混乱的。5.1 MySQL表导出ER关系图的几种做法主流路径有四条按上手难度排序第一条图形化客户端自带逆向功能。Navicat 的逆向数据库到模型、DBeaver 的 ER Diagram 视图、MySQL Workbench 的Database → Reverse Engineer都能一键把指定 schema 画出来。Workbench 那条路径最完整它会把外键关系一并读出来还能导出 PNG 和 PDF。缺点是表一多图就挤成一团100 张表以上基本没法看。第二条命令行/工作台导出 DDL 再导入在线工具。先把结构导成 SQLmysqldump -h 127.0.0.1 -u root -p --no-data --skip-comments mydb schema.sql然后把这个文件贴到在线的结构可视化工具里它会解析CREATE TABLE和外键约束生成图形。这条路的好处是--no-data保证导出的只是结构不会把业务数据带出去。第三条直接查信息模式拼出关系清单。这条路径最灵活适合做批量分析和文档生成SELECT k.TABLE_NAME AS child_table, k.COLUMN_NAME AS child_column, k.REFERENCED_TABLE_NAME AS parent_table, k.REFERENCED_COLUMN_NAME AS parent_column, k.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k WHERE k.TABLE_SCHEMA mydb AND k.REFERENCED_TABLE_NAME IS NOT NULL ORDER BY child_table, child_column;这个查询出来的就是全部外键关系可以直接喂给绘图脚本也可以导入表格工具做人工梳理。第四条建模工具直连数据库逆向。PowerDesigner、DBX 这类工具支持直连数据源做逆向工程能把表结构、主键、外键、索引一次性拉成模型还能做命名规范检查和字段对齐。适合表多、需要长期维护模型的场景。5.2 SQL转ER图在线工具的能力边界在线工具方便但有四条边界必须清楚。第一它只会读 DDL不会读业务。它看到status TINYINT就画一个字段不知道 1 是待支付、2 是已支付。任何语义层面的东西它都给不了必须人工补。第二没有外键约束的库它连不出线。很多业务库为了性能或者历史原因取消了物理外键只靠应用层保证。这种库导出来是一堆孤立的方框关系全靠你自己填。所以逆向之前先统计一下外键数量SELECT COUNT(*) FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA mydb;结果是 0 的话别指望一键出图。第三隐含关系它认不出来。命名约定形成的逻辑外键user_id指向user.id、通过中间表建立的多对多、通过 JSON 字段存的弱关联这些都只能靠人工识别。第四长数字和大字段容易出错。我之前处理过一个库身份证号存在VARCHAR里导出的 DDL 里显示正常但走某些转换链路时被识别成科学计数法回填时精度丢了身份证后几位变成 0。这提醒我逆向工具的输出永远要跟原始 DDL 对一遍尤其是数字型和长字符串。凡是要拿去做数据迁移的先做类型核对。至于把库结构贴到第三方在线服务这件事先看数据敏感度。表名和字段名本身就是资产信息能本地做就本地做实在要用在线工具只传结构不传数据且优先选可以本地部署的方案。5.3 逆向出的图为什么总是不对逆向出来的图有个共性结构正确语义错误。原因是数据库里的一张表未必对应一个业务实体。历史演进会留下很多痕迹已经废弃但没删的字段、为了性能加的冗余列、临时用的中间表、拆表留下的影子表。工具不知道这些它只会把看到的东西全部画上去。我判断一张表是否该进 ER图的流程是先看有没有主键没主键的表大概率是中间表或者日志表再看行数和增长趋势只增不减且没人查的可能已经废弃然后看字段是否有大量空值全空的列基本可以判定废弃最后去代码里搜表名没有任何引用的直接排除。这个过程很土但非常有效。180 张表过一遍通常能砍掉三四十张不该出现在模型里的表剩下的才是真正的业务实体。做完这一步图才谈得上能给人看。6. 工具选型与规范化检查工具不是重点但选错了会很累。6.1 PowerDesigner、DBX这类工具各自站的位置PowerDesigner属于重型建模工具特点是模型层次完整概念、逻辑、物理三层可互相转换、支持多数据库方言、能生成和反向解析 DDL、能做团队模型库。适合中大型项目、需要长期维护数据模型、需要出正式设计文档的团队。缺点是学习曲线陡界面风格偏传统小项目用它属于杀鸡用牛刀。DBX 这类数据库管理工具的重心在管理而不是建模连接管理、SQL 编辑、数据传输、结构对比是它的强项ER 图通常作为附属功能存在。它的价值在于日常运维和结构变更核对比如比对开发库和生产库的结构差异快速定位漏掉的字段和索引。真正做建模我不依赖它。MySQL Workbench / Navicat / DBeaver属于中等重量逆向和正向都能做够用且上手快是大部分项目的实际选择。纯绘图工具各种在线画板、Visio 类工具适合概念层因为完全自由不受工具元素库限制。代价是不能自动生成 DDL图改了表得手动跟着改。我的组合是概念讨论用自由画板逻辑模型进 Weight 中等偏上的工具并保存工程文件物理 DDL 由工具生成后再人工审一遍。工具之间不追求统一追求的是每一层都有明确产出。顺便提一句数据库同步工具。模型定稿之后从开发库到测试库到生产库的结构同步靠手工执行 DDL 迟早出错。结构对比加生成差异脚本这一步能省掉大量为什么测试环境少一个索引的排查时间。这属于模型落地之后的工程环节跟 ER图本身是两件事但值得在模型定稿时就把流程定下来。6.2 轻量方案与版本管理工程文件必须进版本库。ER图不是一次性产物它随需求演进改动历史本身就是重要文档。但工具生成的工程文件通常是二进制或者半结构化格式直接放 Git 里 diff 不出来。我的做法是双轨工程文件入库保证可恢复同时导出一份纯文本的 DDL 也入库用来做 diff。任何模型改动看 DDL 的 diff 就知道改了哪张表哪个字段评审时一目了然。再进一步把建表 DDL 拆成按版本管理的迁移脚本每次模型变更对应一个脚本文件命名带序号和日期。这样模型图和数据库实际状态能对齐新人接手时看脚本列表就知道这个库经历过什么。6.3 从ER图读出范式问题范式检查不用等建表之后在 ER图上就能看出来。第一范式有没有多值属性图上有并列的phone1、phone2或者一个字段要存逗号分隔的多个值就是违反。表现为属性定义里出现多个、列表这类描述。第二范式关联表里有没有只依赖部分主键的列比如选课表主键是(student_id, offering_id)却存了student_name——学生姓名只依赖student_id不依赖整个主键。图上一眼能看出这张表里出现了本该属于某个参与实体的属性。第三范式有没有传递依赖比如学生表里有major_id又有major_name。major_name依赖major_idmajor_id依赖student_id传递依赖成立。图上表现为一个实体的属性里出现了另一个实体的名称字段。这三种情况在图上都非常显眼因为 ER图的表达方式天然把谁的属性标得很清楚。建表前扫一遍比事后改表便宜太多。6.4 反范式与索引不该污染概念模型反范式是物理层的决定不是概念层的。这个概念要分清。业务上订单总金额确实可以从明细算出来这属于概念层的派生属性。但为了查询性能物理表里存一个冗余的total_amount这是物理层的反范式设计。概念图不该因为性能考虑就把total_amount画成一个普通属性——那样后面接手的人会以为它是权威数据。同样索引、分区、字符集、存储引擎一个都不该出现在概念和逻辑图里逻辑图可以标唯一约束因为那是语义的一部分。把这些东西画进模型图图会变成四不像既不是业务沟通工具也不是完整的部署文档。我见过最夸张的一张图每个字段后面标了索引名和索引类型还标了字符集。这张图给业务方看对方直接放弃了沟通。图的信息密度必须跟读者匹配。7. 课程设计与实际工作里最容易翻车的细节7.1 命名与图例规范命名规范这件事在课程设计里是加分项在工作里是必备项。统一用下划线分隔的小写英文表名用单数还是复数选一种就别改外键列名统一用引用表名_id。图上的实体名和表名要能对上不能图上叫学生表里叫t_xs。图例必须放在图上。矩形、菱形、椭圆分别代表什么实线双线区别是什么下划线代表什么都要有一小块说明。评审老师或者同事第一眼看到图靠图例就能读懂不需要你在旁边解释。这一点看着小但它是图能不能独立交付的分界线。还有一个我踩过的坑基数标注的方向。Crows Foot 里那个鸦爪画在哪一端不同教材说法有出入。我的处理办法是图例里明确写出鸦爪表示多然后全图统一避免自己前后不一致。评审时如果被质疑有图例为证。7.2 课程设计的交付物清单课程设计的常见评分点不只是那张图。按完整度排我建议提交这些需求分析文档业务流程描述实体清单实体和属性的判断依据。概念 ER图无物理细节带图例带基数。逻辑模型图含主键、外键、唯一约束。建表 DDL可执行、有外键、有索引、有注释。规范化说明明确到第几范式若有反范式要说明理由。测试数据与典型查询至少覆盖增删改查和两个多表连接。设计说明关键取舍的解释比如为什么拆表、为什么加代理键。最后一项是拉开分差的地方。大部分同学只交图加 SQL把为什么这么设计写清楚的很少。7.3 高频追问与自查清单评审和面试里被问到的概率最高的几个问题我在下面列出自查项追问考点自查点这个实体为什么独立成表不做成属性实体判定能否说出生命周期和引用场景这个关系是几对几有没有可能反过来基数判断举出反例场景主键为什么选这一列加代理键吗主键策略业务唯一性和引用频率有没有多值属性怎么处理的第一范式拆表而不是开多个列删除主记录时关联数据怎么办引用完整性级联、置空还是禁止大表怎么查索引加在哪物理设计高频查询条件和连接列这个字段能推导出来吗数据一致性派生属性的处理策略把这张表过一遍能挡掉八成的追问。剩下的两成通常是具体业务规则的细节那就要靠对业务本身的理解了。我自己现在的习惯是模型定稿前把这七条逐个念一遍念到哪条答不上来就回去补。这个方法用了几年返工率明显下来了。最后分享一个我觉得最省时间的办法先把业务方最常问的三个统计问题写出来然后反推需要哪些实体和关系。比如上个月各院系选课人数、每个客户的账户总余额、每天的交易笔数趋势。这三个问题能跑通说明模型基本是对的跑不通缺哪个实体或关系一目了然。这个思路从需求倒推结构比从名词列表正向推要快得多也更容易发现漏掉的关系。