完全指南:概念、画法、工具与实战案例)
前阵子一个刚转岗做数据开发的同事找我甩过来一张从数据库里导出的“数据字典”两百多行字段说明让我帮他“把业务关系捋一捋”。说实话对着这种纯文本的表结构靠人肉脑补实体之间的联系效率实在太低了。我当时的建议很简单先画一张ER图。很多人觉得ER图就是画几个方框连几条线但真正接手过复杂项目以后你应该能体会到这张图是概念数据建模阶段最核心的沟通工具——它把现实世界里“谁和谁是什么关系”翻译成数据结构之间的“实体-联系”后期所有表设计、索引规划、接口字段对齐都要回到这张图上校准。这篇文章我打算围绕“实体-联系图”这个概念把从入门到实操的一整套内容串起来包括ER图到底在解决什么问题、符号怎么画、主键怎么标、用PowerDesigner和在线工具怎么落地再拿教学管理系统、银行储蓄系统这类经典场景做拆解。不管你是刚学数据库的在校生还是工作中需要快速梳理老系统表结构的开发者应该都能找到可以直接上手的东西。1. 先搞清楚ER图到底在解决什么问题1.1 没有建模的时候我们是怎么被搞崩的我之前接手过一个老项目表有八十多张字段上千个。最痛苦的不是字段多而是没人说得清楚业务规则。比如订单表和客户表到底是一对多还是多对多用户表和角色表之间是不是还藏着个中间表这些信息全都散落在代码的ORM映射里、存储过程的注释里甚至有些干脆只存在于老同事的脑子里。那种状态下改表结构基本等于盲人摸象。你改了一张表的字段类型关联查询可能直接报错你删了一条冗余字段说不定就破坏了某个隐藏依赖。为什么因为缺了一张“地图”。ER图就是这张地图——它把实体可以理解成业务里的人和事物、属性描述实体的具体信息、联系实体之间的业务规则用标准化符号画在一张图上让整个团队在同一个认知层面上讨论数据模型。很多同学觉得既然最后要建表那直接写SQL不就行了非也。SQL描述的是“结果”ER图描述的是“过程和意图”。举个例子你要建一个班级和学生一对一还是一对多的关系SQL里体现出来的可能是学生表加一个class_id外键但你不知道当初为什么这样设计而ER图上双向箭头、基数标注这些符号直接告诉你一个班级最多容纳多少学生、一个学生是否必须属于某个班级。这些业务约束恰恰是数据质量的生命线。1.2 实体、属性、联系ER图的“三件套”ER图的全称是Entity-Relationship Diagram实体-联系图。它由三样东西组成实体Entity业务世界里的独立对象比如学生、教师、课程、订单、客户。在ER图上通常用矩形表示。属性Attribute描述实体的特征比如学生的学号、姓名、出生日期。属性用椭圆表示通过线段和实体相连。联系Relationship实体之间的业务关联比如“学生”选修“课程”“教师”教授“课程”。联系用菱形表示。举一个教学管理系统的例子。学生是一个实体它有学号、姓名、学院等属性课程也是一个实体它有课程号、课程名、学分等属性。学生和课程之间的关系是“选修”一个学生可以选修多门课程一门课程也可以被多个学生选修所以这是典型的多对多联系。这个概念看起来简单但真正建模的时候最容易出问题的地方在于哪些东西该建模成实体哪些东西该建模成属性比如学生的“班级号”看起来像属性但如果班级本身有班主任、有教室号、有年级特征那就应该单独建一个“班级”实体而不是塞在学生属性里。这类判断前期做错了后期返工成本很高。2. ER图怎么画符号规范与主键表示2.1 实体、属性、联系在图上长什么样先解决一个很多人问过我的问题ER图主键怎么表示在经典ER图也叫Chen表示法中实体的每个属性都用椭圆画出主键属性需要在属性名下面加下划线这是最常见的标注方式。比如“学生”实体有学号主键、姓名、性别、出生日期那么学号的下方就要画一条下划线一眼就能看出哪个字段是主键。不过实际工作里面不同工具、不同团队用的ER图表示法并不完全一样。常见的其实有好几套Chen表示法实体矩形、属性椭圆、联系菱形。适合教学和概念建模主键下划线清晰但图面会比较散。Crows Foot乌鸦脚表示法实体矩形联系直接用线加“乌鸦脚”符号表示基数属性挂在实体下方。数据库设计工具比如PowerDesigner的CDM概念数据模型和PDM物理数据模型就常用这种风格。UML风格实体相当于类属性写在矩形内部联系用连线加基数注释。对熟悉面向对象的人更友好。很多在线工具和MySQL Workbench生成出来的“ER图”其实更接近物理模型即直接把表、字段、外键关系画出来并不展示属性和联系之间的语义。严格来说那是关系模型图不是标准ER图。但这并不妨碍项目里把它们统称为“ER图”因为它们的核心用途一致让人看懂表与表之间怎么关联。2.2 主键、外键到底该怎么标主键和外键的概念是ER图和实际建表之间衔接最紧密的部分。主键是实体内唯一标识一条记录的属性或属性组合外键则是在子实体里保存父实体的主键值用来实现联系。在概念层的ER图上主键标注下划线即可。但到了物理表设计阶段主键外键怎么落就有讲究了。比如“学生-班级”这种一对多关系学生表里存班级ID作为外键这个外键在ER图上并不是画在学生实体的属性里而是通过“属于”联系来体现。如果你画图时候把外键画成一个普通属性很容易和业务属性混淆。我建议在物理模型层比如MySQL Workbench导出的图里对外键字段单独用颜色或者字段名前缀标记这样读图的时候不会看漏。复合主键的情况也经常碰到。比如选课表学生选课程通常更适合用“学号课程号”作为联合主键避免重复记录。在ER图上这个选课联系本身可能没有自己的主键但如果选课需要记录成绩、选课时间那它就升级成了“弱实体”或“关联实体”要单独建模并拥有自己的属性。我们在后面章节用教学管理系统详细拆一下。2.3 联系的类型1对1、1对多、多对多怎么画联系类型是ER图最需要反复确认的信息。三种基本类型一对一1:1一个员工对应一个工牌反过来一个工牌也只对应一个员工。图中在两个实体间画一条线两端各标一个“1”。一对多1:N一个班级有多个学生一个学生只属于一个班级。班级端标“1”学生端标“N”或“多”的符号。多对多M:N一个学生选修多门课程一门课程有多个学生选修。两端分别标“M”和“N”。多对多关系特别注意在关系型数据库里不能直接建表因为两张表之间没法用一行外键表达多行对应多行。实际落地必须拆成三张表两张实体表加一张中间表。比如“学生”和“课程”之间的M:N联系在物理模型中要变成“学生表”、“课程表”、“选课表”选课表里存学号和课程号两个外键可能还有成绩等属性。画ER图的时候很多人喜欢把“联系”画得很复杂我个人建议逻辑清楚比画图炫酷重要得多。一对一关系如果业务上不区分实体完全可以合并成一张表一对多关系就是加外键多对多关系就是设计中间表。ER图的意义就在于把这几句话画出来让评审的人30秒内看懂而不是花半小时读你写的文档。3. 从零手画一张ER图以教学管理系统为例3.1 需求梳理阶段先别急着画框很多人画ER图第一步就打开工具开始画矩形我劝你先停一下。画ER图的第一步永远是把业务需求里的名词和动词圈出来。拿“教学管理系统”来说假设业务方给了一段描述学校有多个学院每个学院有若干专业每个专业下有若干班级班级包含学生教师归属于某个学院教师可以讲授多门课程每门课程由一位教师负责学生选修课程选课后期末产生考试成绩。我们从这段话里提取名词学院、专业、班级、学生、教师、课程、成绩。名词大概率是实体。再提取动词包含、归属、讲授、选修、产生。动词大概率是联系。这里有一个经验先不要管这个名词是实体还是属性全部列出来等下一步再筛选。因为业务人员口语里说出来的名词往往会把实体和属性混在一起。比如“学生姓名”这里的“姓名”明显是学生实体的属性不是独立实体但“班级”就可能不是学生属性因为班级有自己的属性专业、年级、教室就应该向上提升为实体。3.2 实体识别与属性划分把初步清单整理一下教学管理系统的核心实体大概有这些实体关键属性主键学院学院编号、学院名称、院长、联系电话学院编号专业专业编号、专业名称、所属学院专业编号班级班级编号、班级名称、所属专业班级编号学生学号、姓名、性别、出生日期、入学年份学号教师教师编号、姓名、职称、所在学院教师编号课程课程编号、课程名称、学分、授课教师课程编号选课学号、课程编号、成绩学号课程编号属性划分有一个判断标准我一直在用如果一个属性下面还有“子属性”或者它自身有独立的业务规则就考虑把它升级为实体。比如“学院”如果只是学生的一个字段可以不放实体但学院有院长、有联系电话还和专业有关系那它就是实体。在概念建模时实体边界模糊非常正常关键是和业务方对齐“这个东西我们以后会不会单独查、单独维护”。会就是实体不会就是属性。3.3 联系梳理与基数标注实体定了下面就是连线。教学管理系统里最常见的几条联系学院和专业1对多一个学院下多个专业一个专业归属一个学院。专业和班级1对多。班级和学生1对多。学院和教师1对多但注意教师是否必须归属学院有的学校行政老师可能不归属教学学院这里业务规则要确认。教师和课程1对多一门课程只有一个责任教师一个教师可带多门课程。学生和课程多对多通过“选课”联系选课联系带属性“成绩”。画出来以后你会发现图看起来就是几个矩形加菱形但里面隐含的约束非常多。比如班级和学生之间是“必须属于且只能属于一个班级”还是“可以暂时未分配班级”ER图上如果用双线或圆点符号表示“必须参与”那么未来设计学生表的class_id外键时是否允许为空就有依据了。这些细节恰恰是ER图相比普通“表关系图”更高层、更有价值的地方。3.4 最终成图检查清单画完一份ER图不要急着说完工。我会习惯性地过一遍检查清单每个实体有没有标主键主键下划线是否清晰每个联系是否标注了基数有没有遗漏1、N、M的标记有没有把属性误画成实体或者把实体误画成属性多对多联系是否已经设计了关联实体或中间表联系上有没有遗漏属性比如成绩非主键属性是否都能通过主键唯一确定如果不能要么表格拆分要么检查是否遗漏了实体。这份清单帮我挡过不少上线前的返工。特别提醒ER图不是画完给领导看一眼就完事的东西它是数据库设计评审的输入物。评审的时候业务方、开发、测试看的是同一张图画得是否严谨直接决定后期沟通成本。4. 工具实操三条最常用的出图路子4.1 PowerDesigner从建模到生成SQL的正向工程PowerDesigner算是老牌建模工具国内很多银行、保险、国企单位还在用。它能画概念模型CDM也能画物理模型PDM并且支持从概念模型转物理模型再生成建表SQL这就是正向工程。用PowerDesigner画ER图的基本流程新建一个Conceptual Data Model概念数据模型。在模型里点中Entity工具在画布上创建实体右键进入属性窗口填写实体名称、编号、属性列表。在属性里添加主键标识选中某字段在下方Primary Identifier区域勾选相当于概念模型的主键标记。使用Relationship工具连接两个实体双击连线在Cardinality里设置基数One-One、One-Many、Many-Many。多对多联系PowerDesigner可以把它自动拆成关联实体在CDM层显示为中间带小矩形的连接。模型检查无误后选择Tools - Generate Physical Data Model选择目标数据库类型比如MySQL、OraclePowerDesigner会自动把实体映射成表把属性映射成字段联系映射成外键或中间表。最后在PDM下选择Database - Generate Database生成完整SQL脚本。PowerDesigner的上手门槛主要是界面老、逻辑层级多概念模型和物理模型容易搞混。我的建议是你先在CDM里把业务语义梳理清楚不要急于生成物理模型。因为概念模型是你和业务部门沟通的语言物理模型是给DBA落地用的两者职责不同混在一起反而是负担。4.2 MySQL Workbench从表结构反向导出ER关系图对于很多已经有数据库表的项目“mysql的表导出er关系图”是个非常高频的需求。MySQL Workbench里的做法很简单Database - Reverse Engineer选择数据库连接或SQL文件工具会自动读取表结构、主外键信息生成物理视图的ER图。这个功能适合做老系统文档梳理。但注意几个坑如果原表的关联关系是通过ORM实体类维护的数据库层面根本没有外键约束那Workbench导出的图就只有孤零零的表没有连线。这种情况要用“虚拟外键”或者自己手工连线Workbench在关系页里可以手工添加。字段特别多的表自动布局会很乱连线段互相交叉。可以手动拖拽但表一多就累我一般按业务模块分批导出再拼图。Workbench生成的图是物理模型图不是概念ER图展示的是表和字段不区分实体和属性。但用于了解现有库的表关系绝对够用。如果你习惯用命令行或快速处理可以用一些Python类库读取information_schema里的表字段和外键信息配合Graphviz生成关系图适合追求自动化的场景。不过对大多数团队来说直接用Workbench就够了没必要为了“全自动”去重复造轮子。4.3 SQL转ER图在线工具快速可视化复杂脚本很多在线搜索“SQL转ER图在线工具”的同学手里可能只有一份建表SQL脚本又不想安装桌面软件。我在项目里也试过几款在线工具比如dbdiagram.io、drawSQL、sqldbm这类基本都支持粘贴DDL语句或者用它们自己的DSL语法定义表关系然后自动渲染出ER图。dbdiagram.io是我用得比较多的一款它使用一种类似Markdown的DSL语法。示例Table students { id int [pk] name varchar class_id int } Table classes { id int [pk] name varchar } Ref: classes.id students.class_id粘贴到编辑器里右侧立即渲染出对应的表关系图导出图片和PDF都很方便。这类工具适合快速做原型展示因为它不用管数据库连接只要SQL或DSL就能出图。不过要提醒一句“SQL转ER图”工具解析的是DDL里的主外键定义如果你的SQL脚本里没有定义外键约束工具再怎么智能也画不出关系连线。很多历史项目为了性能干脆不用外键我遇到这种情况时会先把外键关系整理成一份映射表再按工具支持的语法手工补上连线。核心原则是工具帮你省的是排版时间但关系梳理还是得靠你对业务的理解。4.4 工具选型建议不同阶段选不同工具不需要一种用到黑。我自己的习惯是这样的概念建模阶段和业务讨论业务规则用PowerDesigner或者中规中矩的画图工具重在表达语义不急着贴字段。物理表设计阶段用MySQL Workbench或Navicat直接基于真实表结构调整设计。快速演示和文档交付用dbdiagram.io这类在线工具分享链接或者导出图片都很方便。还有一点补充论最灵活的其实是draw.iodiagrams.net免费且支持自定义形状很多人拿它画ER图。它的优势是模板多、导出格式丰富缺点是默认不带自动布局和数据模型校验实体多了以后容易乱。我的建议是正式建模用专业工具日常草图可以用draw.io别让工具选择拖累建模本身的思路。5. 真实项目案例银行储蓄系统ER图拆解5.1 业务场景与实体梳理“银行储蓄系统ER图”这个关键词几乎每年都有人搜因为它太典型了涉及客户、账户、交易流水等核心实体既有父子关系又有流水型数据用来理解ER图刚刚好。假设我们要设计一个简化版的银行储蓄系统业务规则如下一个客户可以开立多个储蓄账户一个账户只能归属于一个客户。账户分为活期账户和定期账户但都是账户。客户通过柜台或自助渠道办理存取款业务每笔存取款都产生一条交易流水。交易流水必须记录交易类型存款、取款、交易金额、交易时间、经办柜员。抽取出来核心实体大概有客户、账户、交易流水、柜员可以理解为内部员工实体。5.2 客户、账户、交易之间的关系分析客户和账户是一对多联系一个客户有多张账户。这个联系在物理模型中体现在accounts表里的customer_id外键。账户和交易流水是一对多联系一张账户有多笔存取款记录。所以在transactions表里会存account_id外键。客户和柜员之间没有直接业务联系所以不需要连。但柜员和交易流水有联系一笔业务由哪个柜员经办。这里注意柜员和交易流水也是一对多联系。这个例子里特别值得品味的是“账户类型”的设计。活期账户有日利率定期账户有存款期限、到期日。如果直接在一个账户表里把所有字段都塞进去会出现大量空字段浪费存储而且不好维护。模型上可以考虑用“继承”的方式抽象出一个账户父实体再分出活期账户和定期账户两个子实体子实体继承账户号作为主键并增加各自特有属性。在ER图上这相当于一个ISA关系物理模型落地时可以用单表、类表继承或拆表等方式实现。5.3 从ER图到建库脚本把上述ER图转成建表SQL大致的思路是client表主键client_id唯一约束身份证号或手机号。account表主键account_id外键customer_id指向client表账户状态、账户类型作为普通字段。transaction表主键transaction_id外键account_id以及金额、时间、经办柜员ID和交易类型。注意账户和交易流水之间如果按ER图设计是一对多我们通常不会在account表里放最近交易金额这类冗余字段因为那违反第三范式。但实际银行系统为了读性能可能故意在账户表里冗余一个balance余额字段这就引出了一个概念反规范化。ER图是理想化的概念结构物理表设计可以根据性能需求做调整但在做调整之前你必须有一张“标准版”ER图才知道改动到底偏离了哪里。这也是我在带新人时常强调的一句话ER图不是一锤子买卖概念模型和物理模型本来就可以不一样。关键是你得能说清楚差别为什么存在代价是什么。6. 常见问题与排查技巧实录6.1 实体还是属性分不清怎么办几乎每次建模评审都会因为“某个字段到底是实体还是属性”争论起来。比如学生的“籍贯”国家、省、市看起来都是属性但如果系统里有“按地区统计招生人数”的需求地区就该单独建模或者至少拆成省市县三段字段而不是把一个文本字段“籍贯”塞进去后期想按市统计都得用LIKE匹配血泪教训。我的判断标准是三层它有没有独立的属性有独立属性就升级为实体。它要不要被其他实体引用如果有两个实体都关联这个信息就应该是实体。它是否需要被大量查询和统计需要就实体化不需要就继续当属性。按这三个问题过一遍大部分争议都能落地。6.2 多对多关系到底要不要拆拆而且要在概念建模时就拆清楚。很多新人画ER图学生和课程之间的多对多就画一个菱形然后建表时发现选课表里要放成绩、放选课时间才发现当初如果不光把联系画出来还要把联系升级成“关联实体”后续就不会那么被动。ER图里关联实体用矩形嵌套菱形表示意思是这个联系本身带有属性。尽早识别关联实体能让后续物理模型的中间表设计变得非常顺利。6.3 工具生成的图乱、没法看怎么办自动布局是工具的通病。我的经验是对于超过20张表的模型不要指望自动排列能生成一张能直接放进文档的图。正确做法是按业务模块拆分比如“用户模块”、“订单模块”、“支付模块”每个模块单独出一张ER图。模块之间的关系单独画一张“上下文图”不需要展开所有字段。每张图的实体数量控制在10个以内保证可读性。这其实和代码组织是同一个思路分层、模块化。ER图如果巨细无遗地塞在一张图里效果反而不如分层的图册。6.4 画了图就以为万事大吉图会过期的这是一个我特别想提醒所有人的点。ER图最怕的不是画得丑而是画完没人维护。老系统改造项目里我见过太多ER图和实际表结构严重不一致的情况最后新同事照着ER图做开发上线就出问题。所以实操上我会养成两个习惯数据库表结构变更时顺手把对应的ER图也更新一遍哪怕只是改一个字段名。这个投入很小但收益非常大。定期用工具逆向生成实际表关系图和文档里的ER图做对比。差异的地方往往就是技术债积累最多、最需要重构的地方。7. 一点个人经验分享做了这么多年数据建模我自己最深的体会是ER图最值钱的不是那张画出来的图而是画的过程中逼着所有人把业务规则说清楚。很多模棱两可的业务问题平时开会讨论的时候大家都是“应该对吧”、“差不多吧”一到画ER图必须给出精确答案一个学生到底能不能同时属于两个班级一笔交易到底能不能没有账户这些问题在图上统统藏不住必须画出唯一的解释。如果你现在正在学ER图我的建议是不要只看书上的例子一定要拿一个真实业务来练手。你所在学校、公司、甚至小区物业的日常运作都可以当作建模对象。画一遍、找同事或朋友评审一遍、再试着生成建表SQL这一套流程走下来你对实体、属性、联系的理解会完全不一样。工具只是手段能把业务逻辑翻译成清晰的数据结构才是这门手艺真正值钱的地方。