实体-联系模型与ER图:从概念设计到关系模式转换的完整实践
发布时间:2026/9/19 1:50:43 锦皓数字建站

简介一份讲解数据库系统概念建模的PPT课件围绕实体-联系ER模型展开面向数据库初学者、高校学生及需要快速梳理概念设计知识的备考者。内容系统覆盖信息世界基本概念包括实体、属性、码、域、实体型与实体集并重点分析两个实体型、多个实体型及单个实体型内部的一对一、一对多、多对多联系配合映射基数说明及丰富的ER图示例帮助读者理解抽象概念与图形化建模方法。资源为单个PPT文件压缩包大小622KB便于直接打开学习或用于课堂展示目前已有411人学习浏览适合课前预习、课后巩固或作为教学设计参考。通过本课件可快速建立数据库概念模型框架理清实体间联系与ER图绘制规范为后续关系模型转换和数据库逻辑设计打下基础。1. 实体-联系模型是数据库设计的“第一张草图”绝大多数数据库设计翻车不在 SQL 写得差而在 ER 图阶段少问了一句“这是一对多还是多对多”。实体-联系模型就是用实体、属性、联系三个构件把业务语义画成一张可评审的图ER 图则是这张图的表达形式。在《数据库系统概论》国内高校用的王珊、萨师煊版本已更新到第六版里E-R 模型是整个概念设计章节的地基但它不只是考试课它是团队对齐需求、转关系模式、排查冗余结构的起点。这里按实体-联系模型从概念到落地的路径走一遍覆盖 ER 图怎么画、主键怎么标、联系怎么定以及从 ER 图转换到关系表时的常见坑最后落到工具和自查技巧。2. 实体、属性、联系把现实世界翻译成 ER 图的三个构件E-R 模型的表达力来自三个图形符号矩形表示实体集椭圆表示属性菱形表示联系。这套命名从 Chen 提出的 Entity-Relationship Model 沿用至今。绘图本身不难真正决定设计质量的是“分界线怎么划”——什么时候一个名词该建实体什么时候该挂成属性什么时候该画一条联系。2.1 实体与属性分界线在“要不要单独维护”业务里最常见的争论是“学校名称算学生的属性吗”“手机号算客户的属性吗”。通常我会先问一个问题这个值如果发生变化是否会同时影响多条记录把“学校名称”作为学生的属性全校上万个学生记录都要冗余存储一次学校改名时需要全表更新漏掉一条就出现数据不一致。把“学校”拆成独立实体学生表只存 school_id学校名称只维护一份这是典型的从“会不会被复用”判断实体边界的思路。判定的常用标准有三条该名词对应的数据是否会被多处引用比如“银行网点”会被多个柜员、多台设备引用该名词是否有独立于当前实体的增、删、改生命周期比如“客户”即使没有账户也还存在于系统中该名词是否天然是复数集合“订单明细”绝不会只有一条“账单”往往是多条的。如果以上任意一条成立就应该建实体而不是把它的全部信息压成某个实体的属性。反过来一个只修饰当前实体、不会被其他地方引用的描述如客户的出生日期就老老实实做属性。2.2 属性与主键ER 图中主键的标准画法“er图主键怎么表示”是高频搜索。标准的 Chen 风格画法是在该属性名的下方画一条下划线代表它是这个实体集的主键。比如“客户”实体下“身份证号”加下划线阅读时读作“客户的主键是身份证号”。没有主键的实体集在真正的实体-联系模型里是不完整的。多值属性用双椭圆表示。一个客户留了三个手机号码这三个号码不是三个属性列而是一个“联系电话”属性取值为一个集合。转换到关系表时多值属性不能直接塞成一个字段否则就违反第一范式通常拆出一张从表或中间表来容纳这些值。派生属性用虚线椭圆表示。账户的“余额”可以由流水累计得出属于派生属性。这类属性在 ER 图上标注出来是为了提醒转换到关系模式时不要贸然建一个物理列去存储否则每次存取款都要同步更新“余额”既容易丢更新也容易造成数据不一致。需要刻意区分的一点外键不是 ER 图里的符号。外键是从 E-R 模型转换到关系模式时才出现的概念。如果画 ER 图时就在实体框里写“customer_id (FK)”等于把逻辑模型混进了概念模型评审时才看不出语义问题。2.3 联系与基数三种联系的判别方法联系在 ER 图里是菱形菱形里写动词“选修”“下单”“开户”。判断联系的类型不能靠感觉要靠两个反向提问从 A 的实例出发最多对应几个 B 的实例从 B 的实例出发最多对应几个 A 的实例。联系类型判别特征典型示例转关系模式时的处理1:1A 的一端最多 1B 的一端最多 1部门与部门经理一端主键并入另一端表或低频时合并为一张表1:NA 的一端最多 NB 的一端最多 1客户与账户N 端表中加入 1 端表的主键作为外键M:NA 的一端最多 NB 的一端最多 N学生与课程必须新建中间表两端主键联合做主键判别时最有效的话术是一个客户能开多个账户所以从客户看账户是多一个账户只能属于一个客户所以从账户看客户是一合起来是 1:N。反过来一个学生选多门课、一门课被多个学生选两个方向都是多就是 M:N。还有一个容易被忽略的实体变体弱实体。弱实体自己没有完全的主键必须借助所属实体的主键才能唯一标识。典型的例子是“订单明细”明细的行号只在订单内部有意义离开订单号明细 2 号是谁的ER 图中弱实体用双矩形弱联系用双菱形转换关系模式后把外部实体的主键并入自身主键形成联合主键。3. 从需求到 ER 图以银行储蓄系统为例的建模流程搜索里“银行储蓄系统er图”出现频率很高下面用它把完整流程走一遍。建模不是坐下就画矩形而是“需求采集 → 边界圈定 → 实体候选 → 属性补充 → 联系定基数”五步递进。3.1 第 0 步与第 1 步圈定系统边界从名词里挑候选实体先确定这个系统管什么、不管什么。银行储蓄系统的边界是“存取款及相关账户管理”利率市场化调整、贷款审批不在边界内。然后打开需求文档把名词全部圈出来客户、账户、储蓄卡、存款记录、取款记录、流水、银行网点、柜员、利率表、地址、电话、余额。这些名词不可能全部成为实体。按上一章的标准筛一遍“利率表”被多个账户产品引用且利率会调整建独立实体“余额”可由流水计算属于派生属性不建实体“电话”“地址”是客户或网点的描述属性先挂在对应实体下后面看是否多值再决定是否拆表“存款记录、取款记录”本质都是账户下的资金变动统一抽象成“交易流水”一个实体避免后面画图时出现多条平行的“存款联系”“取款联系”。这一步产出的是一个候选实体清单客户、账户、储蓄卡、交易流水、银行网点、柜员、利率表。3.2 追加属性并圈定主键给每个候选实体补属性。“客户”实体需要有身份证号、姓名、手机号、住址“账户”实体需要有账号、开户日期、币种、账户状态“交易流水”实体需要有流水号、交易类型、交易金额、交易时间、交易后余额。主键判定这里有一个顺序先找业务主键没有业务主键再考虑自增代理主键。“客户”用身份证号做主键时要注意实际系统里会出现一个身份证对应多个客户号柜面渠道和线上渠道建了两个客户档案所以银行业普遍用内部生成的客户号做主键。这样在 ER 图阶段就把“业务上唯一”和“技术上唯一”区分清楚了。手机号在这个实体集里是一个多值属性因为一个客户可能留了家庭电话、办公电话、手机三个号码。在 ER 图上客户的“联系电话”画成双椭圆右端连着客户矩形。这一笔处理后面转关系模式时会直接决定要不要多建一张联系方式表。3.3 用已有数据验证基数假设而不是只信需求会议需求评审会上产品经理说“一个客户可以开多个账户”这是需求方的意图不等于存量数据就是这样的。尤其在接手遗留系统时写代码前我会先对真实数据做一次基数探测用事实修正 ER 图的连线。探测“账户-流水”是否为 1:N执行下面的 SQL-- 验证: 一个账户是否对应多条流水 -- 若返回非空行, 说明至少存在一对多关系 SELECT account_id, COUNT(*) AS tx_count FROM transaction_tbl GROUP BY account_id HAVING tx_count 1 LIMIT 5;逻辑说明按 account_id 分组统计每个账户下的流水条数HAVING 过滤出条数大于 1 的账户。如果查询结果为空说明当前数据里每个账户最多只有一条流水需要进一步和业务方确认是否存在存量数据清理导致的信息丢失不能直接据此认定 1:1。如果返回 5 行每个 account_id 的 tx_count 都大于 1则“账户到流水是一对多”的假设得到了数据支撑。同样的探测可以反向做一次验证“流水-账户”不会出现一条流水归属多个账户的情况-- 验证: 一条流水是否只属于一个账户 SELECT transaction_id, COUNT(DISTINCT account_id) AS acct_cnt FROM transaction_tbl GROUP BY transaction_id HAVING acct_cnt 1;参数说明COUNT(DISTINCT account_id) 统计单条流水关联的不同账户数如果结果非空说明流水与账户是多对多ER 图上这条线就要重画通常意味着“流水”里还隐藏着一个“被拆分的交易”实体。3.4 处理多值属性与派生属性后再定稿客户的多值属性“联系电话”拆成“客户联系方式”实体与原“客户”实体形成 1:N 联系外键为 client_id。账户的“余额”作为派生属性在 ER 图上保留虚线椭圆标注但转关系表时不在账户表里建列。这里有一个可复用的判断如果业务要求快速展示“账户可用余额”且流水量很大每次实时汇总性能不够那么可以专门建一张“账户余额快照表”每天晚上批量重算。快照表在 ER 图上应作为一个独立实体出现它的行数等于账户数和流水表的数量级不同不要把它当成派生属性挂掉。3.5 合并与简化消灭冗余联系实体和属性都齐了以后审视联系是否存在冗余路径。一个典型场景客户到流水是否要直接画一条“客户-流水”联系从语义上说客户和流水确实间接相关但中间已经存在“客户-账户”“账户-流水”两条联系。如果再加一条“客户-流水”造成的后果是评审人员容易误认为流水可以直接挂在客户下而产生扇出fan trap转关系模式时也可能诱导开发者写出跳过账户表的跨表查询。正确做法是删掉这条冗余联系保持 ER 图的路径唯一性。同样的流程换成教学管理系统也一样学生、课程、教师、教务员四个实体“选修”联系连接学生和课程“授课”联系连接教师和课程中间不会再画“学生-教师”的直线。这套“从名词出发→逐层筛选→用数据验证”的做法可以复用到任何系统的 ER 建模。4. 从 ER 图到关系模式转换规则与容易踩的坑ER 图的价值最终体现在能不能正确变成一组表结构。转换过程有明确规则也有大量“看着对、做起来错”的细节。4.1 三条转换规则背熟不如用熟联系类型转换策略需要加的约束1:1将一端实体表的主键并入另一端实体表作为外键FOREIGN KEY UNIQUE1:N将 1 端实体表的主键并入 N 端实体表作为外键FOREIGN KEY 普通索引M:N新建中间表两端实体表的主键都进入中间表联合主键或 联合唯一索引1:N 合并时外键加在 N 端。比如“账户”是 N 端那么账户表里要有 bank_id 指向网点表。为什么不能放在 1 端因为把外键放在“网点”表里一个网点维护一个账户就限制了这个网点只能服务一个账户。M:N 必须新建中间表。比如“客户”和“账户”是 M:N一个客户可开多个账户一个账户可有多个联合持有人中间表里放 client_id 和 account_id。中间表的主键由两端主键联合构成联合主键天然保证同一对关系只能插入一次。1:1 是三种类型里自由度最大的。如果两边属性几乎总是一起查询、生命周期相同比如“用户”和“用户档案”我一般建议直接合并成一张表只有在两个对象的数据敏感级别不同、访问频率差异极大时才拆开比如把登录凭据和用户资料分表。拆开时哪一端并入哪一端取决于查询入口经常从哪边出发查对面就把哪边的主键放进对方的表。4.2 从银行储蓄系统 ER 图落成 DDL把上一章设计的 ER 图按规则转成 SQL。核心语句如下-- 1:N: 账户表保留 bank_id 外键, 指向网点表 CREATE TABLE account ( account_id BIGINT PRIMARY KEY, client_id BIGINT NOT NULL, bank_id BIGINT NOT NULL, currency_code CHAR(3) NOT NULL, status TINYINT NOT NULL DEFAULT 1, open_date DATE NOT NULL, CONSTRAINT fk_account_client FOREIGN KEY (client_id) REFERENCES client(client_id), CONSTRAINT fk_account_bank FOREIGN KEY (bank_id) REFERENCES bank(bank_id) ); -- 联系属性: “开户”发生在某个时点, 放在账户表上更合适 -- 如果开户渠道、开户柜员只在开户时有效, 可以挂在账户表逻辑说明账户表通过两个外键同时连接“客户”表和“网点”表分别对应“客户-账户”的 1:N 和“网点-账户”的 1:N。client_id 和 bank_id 都使用了 NOT NULL因为任何一个账户都必须能追溯到唯一客户和唯一网点。再看 M:N 的中间表写法-- M:N: 客户与账户的联合持有关系 CREATE TABLE account_client ( account_id BIGINT NOT NULL, client_id BIGINT NOT NULL, holder_type CHAR(1) NOT NULL, -- 主持有人/副持有人, 属联系属性 create_time DATETIME NOT NULL, PRIMARY KEY (account_id, client_id), CONSTRAINT fk_ma_acct FOREIGN KEY (account_id) REFERENCES account(account_id), CONSTRAINT fk_ma_client FOREIGN KEY (client_id) REFERENCES client(client_id) );参数说明联合主键 (account_id, client_id) 是这里的关键它同时承担了“关系唯一”和“查询主路径”两个职责。holder_type 是联系自身的属性比如区分主账户持有人和共同持有人这类属性只能挂在中间表上挂到客户表或账户表都会造成语义错位。4.3 转关系时常见的三个“看着没问题其实错了”第一个是把多值属性直接建成单列。客户有三个电话开发者在客户表里建 phone1、phone2、phone3 三列或者用逗号拼在一个 phone 字段里。前者扩展性差后者违反第一范式且无法用索引查询。正确做法参照上一章的判断如果号码数量有限且固定可以拆成三个可空列如果数量不固定就建子表。第二个是为派生属性建物理列。账户表存了一个 balance 列业务在每次交易后同步更新它结果出现并发时丢失更新或对账时余额和流水对不上。派生属性要么用视图实时计算要么用“余额快照表”定期重算并把余额的准确性纳入对账流程。第三个是 M:N 中间表用了自增主键却没加联合唯一约束。中间表 id 自增、PRIMARY KEY(id)、但没有 UNIQUE(account_id, client_id) 时同一个客户和同一个账户的关联关系可以插入两次。查询统计时出现重复计数。标准做法是联合主键或者联合唯一索引自增 id 仅作为辅助不要让它成为唯一防线。5. 用工具落地 ER 图逆向工程与设计质量自查手画 ER 图适合学习和评审工程落地时建议用工具。MySQL Workbench 是覆盖面最广的选择功能上支持从现有表结构逆向生成 ER 图打开 Workbench选择菜单 Database → Reverse Engineer按向导连接目标实例选中要导出的 schema工具会读取全部表、字段、外键约束自动生成一张含连线关系的 ER 图之后通过 File → Export 导出为 SVG 或 PNG 直接贴进设计文档。对于一张表写好了 SQL 但还没建库的场景可以找支持 SQL 转 ER 图在线工具把 CREATE TABLE 和 ALTER TABLE 语句粘贴进去工具解析外键后自动出图适合快速检查别人设计的表结构。再往前一层PowerDesigner 是经典教材里常提的重量级工具流程是先在 CDM概念数据模型里画实体和联系再一键转成 PDM 物理模型生成建表脚本适合需要严格管理设计文档的团队。逆向生成的 ER 图只能反映当前物理表结构查不出“该建索引却没建”的问题。我常用一张自查 SQL 检查外键列上是否缺少索引-- 检查所有外键约束是否对应有索引 SELECT kcu.table_name, kcu.column_name, kcu.constraint_name, IF(stat.index_name IS NULL, NO INDEX, OK) AS idx_status FROM information_schema.KEY_COLUMN_USAGE kcu LEFT JOIN information_schema.STATISTICS stat ON stat.table_schema kcu.constraint_schema AND stat.table_name kcu.table_name AND stat.column_name kcu.column_name WHERE kcu.referenced_table_name IS NOT NULL AND kcu.table_schema your_database_name;逻辑说明子查询把外键定义和 STATISTICS 做列名级匹配检查每一条 FOREIGN KEY 对应的列上是否真实存在索引。返回 idx_status 为 NO INDEX 的行就是性能隐患。参数说明your_database_name 替换为实际库名外键如果有复合索引的一部分STATISTICS 表里可能只匹配到其中一列此时需要人工确认复合索引的列顺序是否能覆盖外键查询。最后给一个成本最低的长期习惯ER 图阶段就统一命名。主键统一命名为 id 或 实体名_id外键统一命名为 关联实体名_id联系表用两实体名加下划线连接account_client主键一律联合主键或带前缀的代理键。命名统一后任何一张 ER 图转出来的 SQL 都能被别人秒懂也不需要额外画一张“命名对照表”。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。