1. 数据库设计过程 (Design Process)
数据库设计是一个多阶段的过程,从抽象的需求分析到具体的物理实现。
- 需求分析 (Requirements Analysis):
- 做什么: 充分了解潜在用户的数据库需求。
- 例子: 为一个大学系统进行需求分析。
- 用户需求:
“我们需要跟踪学生、教授和课程。学生需要注册课程,教授需要教授课程。我们还需要记录学生的成绩。”
- 用户需求:
“我们需要跟踪学生、教授和课程。学生需要注册课程,教授需要教授课程。我们还需要记录学生的成绩。”
- 做什么: 充分了解潜在用户的数据库需求。
- 概念设计 (Conceptual Design):
- 做什么:
选择一个数据模型(如E-R模型),并将需求转换为概念模式(E-R图)。
- 例子: “学生”、“教授” 和 “课程”
都是实体。“注册” 和 “教授”
是关系。
- 做什么:
选择一个数据模型(如E-R模型),并将需求转换为概念模式(E-R图)。
- 逻辑设计 (Logical Design):
- 做什么:
将概念模式(E-R图)转换为数据库的逻辑模式(例如,关系型数据库的表结构)。
- 例子: 将E-R图转换为
student表、course表和takes(注册) 表。
- 做什么:
将概念模式(E-R图)转换为数据库的逻辑模式(例如,关系型数据库的表结构)。
- 物理设计 (Physical Design):
- 做什么:
决定数据库的物理存储布局,如索引和文件组织。
- 例子: 决定为
student表的ID字段创建索引,以加快查询速度。
- 做什么:
决定数据库的物理存储布局,如索引和文件组织。
2. E-R模型的核心概念
E-R模型使用三个基本概念:实体集、关系集 和 属性。
2.1 实体与实体集 (Entity Sets)
- 实体 (Entity):
一个在企业中可区分于其他对象的”事物”。
- 例子: 某个特定的学生 “张三”。
- 例子: 某个特定的学生 “张三”。
- 实体集 (Entity Set):
共享相同属性的同类型实体的集合。
- 例子:
student(所有学生的集合)。
- 例子:
- 主键 (Primary Key): 唯一标识实体集中每个成员的属性子集。
💡 如何画图:实体集
- 使用矩形表示实体集。
- 属性列在矩形内。
- 主键属性加下划线。
[ student ] |----------------| | _ID_ | <-- 主键 | name | | tot_cred | |----------------|
2.2 属性 (Attributes)
属性是实体的描述性特性。
- 简单属性 (Simple): 不可再分的原子值。
- 例子:
student的ID。
- 例子:
- 复合属性 (Composite): 可分解为更小的子部分。
- 例子:
name属性,可分解为first_name,middle_initial,last_name。
- 例子:
- 多值属性 (Multivalued):
一个实体在该属性上可以有多个值。
- 例子:
instructor的phone_numbers属性,一个教授可以有多个电话号码。
- 例子:
- 派生属性 (Derived): 其值可以从其他属性计算得出。
- 例子:
age属性,可以从date_of_birth(出生日期) 派生。
- 例子:
💡 如何画图:复杂属性
- 复合属性: 使用缩进表示层级。
- 多值属性: 使用花括号
{ }括起来。
- 派生属性: 使用括号
( )括起来。[ instructor ] |--------------------------| | _ID_ | | name | <-- 复合属性 | first_name | | last_name | | { phone_number } | <-- 多值属性 | date_of_birth | | age() | <-- 派生属性 |--------------------------|
2.3 关系与关系集 (Relationship Sets)
- 关系 (Relationship): 多个实体之间的关联。
- 关系集 (Relationship Set): 同类型关联的集合。
- 关系集的属性 (Attributes on Relationship Sets):
关系本身也可以有属性。
- 例子:
student和course之间的takes关系可以有一个grade(成绩) 属性。
- 例子:
- 关系集的度 (Degree):
- 二元 (Binary): 涉及两个实体集,最常见。
- 三元 (Ternary): 涉及三个实体集。
- 例子:
proj_guide关系,关联instructor,student, 和project。
- 例子:
- 二元 (Binary): 涉及两个实体集,最常见。
💡 如何画图:关系集
- 使用菱形表示关系集。
- 关系集的属性(如果有)从菱形引出。
(date) | | [ instructor ] | [ student ] |------------| | |---------| | _ID_ |--------< advisor >-------| _ID_ | | name | < > | name | |------------| ( ) |---------|
advisor是关系集。
date(学生开始被指导的日期) 是advisor关系集上的一个属性。
3. 约束 (Constraints)
3.1 映射基数 (Mapping Cardinality)
表示一个实体通过关系集能关联的实体数量。
- 一对一 (One-to-one):
- 例子:
一个学生最多管理一个储物柜,一个储物柜最多被一个学生管理。
- 画法: 两边都是箭头 (→)。
- 例子:
一个学生最多管理一个储物柜,一个储物柜最多被一个学生管理。
- 一对多 (One-to-many):
- 例子:
一个导师可以指导多名学生;一个学生最多只能有一个导师。
- 画法: “一”端是箭头 (→), “多”端是直线 (—)。
- 例子:
一个导师可以指导多名学生;一个学生最多只能有一个导师。
- 多对多 (Many-to-many):
- 例子:
一个学生可以选修多门课程;一门课程可以被多名学生选修。
- 画法: 两边都是直线 (—)。
- 例子:
一个学生可以选修多门课程;一门课程可以被多名学生选修。
💡 如何画图:基数 (l..h)
一种更精确的表示法是
l..h(min..max)。
- 例子: 需求:“一个学生必须有且仅有 1 个导师 (1..1);一个导师可以指导0个或多个学生 (0..*)。”
[ instructor ] 0..* (advisor) 1..1 [ student ] |------------| < > |---------| | _ID_ |----------< >-----------| _ID_ | | name | < > | name | |------------| ( ) |---------|
3.2 参与约束 (Participation)
- 全部参与 (Total):
实体集中的每个实体都必须参与至少一个关系。
- 例子:
每个学生都必须有一个导师。
- 例子:
每个学生都必须有一个导师。
- 部分参与 (Partial): 实体可以不参与任何关系。
- 例子: 部分教授可能没有指导学生。
💡 如何画图:参与
- 全部参与: 使用双线连接到菱形。
- 部分参与: 使用单线连接。
[ instructor ] [ student ] |------------| (advisor) |---------| | _ID_ |----------< >=======| _ID_ | | name | (部分) < > (全部) | name | |------------| ( ) |---------|
3.3 弱实体集 (Weak Entity Sets)
- 定义: 没有足够属性形成主键的实体集。
- 依赖: 它的存在依赖于一个”标识”强实体集。
- 辨别符 (Discriminator):
用于区分依赖于同一个强实体的弱实体的属性(也叫部分键)。
- 例子:
section(开课) 是一个弱实体集,它依赖于course(课程)。section的sec_id,semester,year只是辨别符,它们必须结合course的course_id才能唯一标识一个section。
💡 如何画图:弱实体集
- 弱实体集: 双矩形。
- 标识关系: 双菱形。
- 辨别符: 虚下划线。
- 弱实体集对其标识关系的参与总是全部的(双线)。
[ course ] |----------------| | _course_id_ | <-- 强实体的主键 | title | |----------------| | | (单线) | << sec_course >> <-- 双菱形 (标识关系) << >> || || (双线,全部参与) || [[ section ]] ||================|| <-- 双矩形 (弱实体) || _sec_id_ || <-- 虚下划线 (辨别符) || _semester_ || || _year_ || ||================||
4. 扩展E-R特性 (Extended E-R Features)
4.1 泛化与专业化 (Generalization / Specialization)
- 专业化 (Specialization):
自顶向下。在高层实体集中定义有区别的子组。
- 泛化 (Generalization):
自底向上。合并共享特征的低层实体集。
- 属性继承 (Attribute Inheritance):
低层实体集继承高层的所有属性和关系。
- 约束:
- Disjoint (不相交):
一个高层实体最多属于一个低层子集。
- Overlapping (重叠):
一个高层实体可以同时属于多个低层子集。
- Total (全部):
高层实体必须属于某个低层子集。
- Partial (部分): 高层实体可以不属于任何低层子集。
- Disjoint (不相交):
一个高层实体最多属于一个低层子集。
💡 如何画图:专业化/泛化
- 使用一个
ISA三角形(“is a”)连接。
- 例子:
person(人) 是一个高层实体。instructor(导师) 和student(学生) 是其专业化子集。instructor继承person的ID,name等属性,并有自己的salary(薪水)。student有自己的tot_credits(总学分)。[ person ] |------------| | _ID_ | | name | |------------| | /_\ <-- ISA 三角形 |ISA| /_____\ / \ / \ [ instructor ] [ student ] |------------| |-----------| | salary | | tot_credits | |------------| |-----------|
4.2 聚合 (Aggregation)
- 定义:
一种抽象,允许我们将一个关系集(及其关联的实体)视为一个抽象的实体。
- 用途: 允许在”关系”和其他实体(或关系)之间建立关系。
💡 如何画图:聚合
- 例子: 考虑三元关系
proj_guide(关联instructor,student,project)。如果我们想为这个指导关系本身添加一个evaluation(评价)。
- 画法: 我们将
proj_guide关系及其三个实体聚合起来(用一个大方框框住),然后让evaluation实体通过eval_for关系连接到这个聚合体上。+-----------------------------------------+ | [ instructor ] | | | | | \----< proj_guide >----[ student ] | <-- 被聚合的关系 | / | \ | | / | \ | | [ project ] | | +-----------------|-------------------------+ | | < eval_for > < > | [ evaluation ]
5. E-R设计决策 (Design Issues)
在建模时,你必须做出选择:
5.1 实体集 vs. 属性 (Entity Sets vs. Attributes)
- 问题:
phone_number(电话) 应该作为instructor的一个属性,还是一个单独的phone实体?
- 决策:
- 作为属性: 如果你只需要存储号码,可以将其设为
instructor的多值属性{phone_number}。
- 作为实体集: 如果你还想存储关于电话的额外信息(比如
location(位置) 或type(类型)),那么最好将其建模为一个实体集phone,并与instructor建立关系。
- 作为属性: 如果你只需要存储号码,可以将其设为
5.2 实体集 vs. 关系集 (Entity Sets vs. Relationship Sets)
- 问题:
registration(注册) 应该是一个实体,还是student和section之间的一个关系?
- 决策:
- 作为关系:
如果”注册”只是简单地连接学生和课程,并可能带一个
grade属性,那么它是一个多对多关系 (例如takes)。
- 作为实体集:
如果”注册”这个行为本身需要参与其他关系(比如
registration实体需要关联到payment(支付) 实体),那么就必须将其建模为一个实体集registration。
- 作为关系:
如果”注册”只是简单地连接学生和课程,并可能带一个
5.3 二元 vs. 非二元关系 (Binary vs. Non-Binary)
- 问题: 涉及 A, B, C 三者的关联,是用一个三元关系
R(A, B, C)还是用多个二元关系?
- 决策:
- 非二元 (三元): 当 A, B, C
必须同时出现才能描述一个事实时使用。
- 例子:
proj_guide(导师, 学生, 项目)。这三者必须捆绑在一起。
- 例子:
- 二元: 当关系可以被分解时使用。
- 例子:
parents(孩子, 父亲, 母亲)。这最好用两个二元关系father_of(孩子, 父亲)和mother_of(孩子, 母亲)来代替,因为一个孩子可能只知道父亲或只知道母亲。
- 例子:
- 非二元 (三元): 当 A, B, C
必须同时出现才能描述一个事实时使用。
6. 将E-R图转换为关系模式 (Reduction to Schemas)
这是从概念设计(E-R图)到逻辑设计(表结构)的步骤。
转换强实体集:
- 每个强实体集转为一个独立的表,属性即为表的列。
- E-R图:
student(ID, name, tot_cred)
- 表 (Schema):
student(ID,name,tot_cred)
- 每个强实体集转为一个独立的表,属性即为表的列。
转换弱实体集:
- 转为一个表,包含其所有属性,并包含其标识强实体集的主键(该主键是新表的外键,也是主键的一部分)。
- E-R图:
section(辨别符:sec_id,sem,year) 依赖于course(主键:course_id)。
- 表 (Schema):
section(course_id,sec_id,sem,year)
- 转为一个表,包含其所有属性,并包含其标识强实体集的主键(该主键是新表的外键,也是主键的一部分)。
转换关系集:
- 原则:多端合并:要在many的那一端添加另外一端的主键作为外键
- 多对多 (M:N):
必须转为一个新的表。该表包含参与的两个实体集的主键(共同作为主键)以及关系自身的属性。
- E-R图:
student–advisor–instructor
- 表 (Schema):
advisor(s_id,i_id)
- E-R图:
- 一对多 (1:N):
不创建新表。将”一”端的主键,添加到”多”端的表中,作为外键。
- E-R图:
instructor(N) –inst_dept– (1)department
- 表 (Schema):
instructor(ID,name,salary,dept_name) (dept_name是外键)。
- E-R图:
- 一对一 (1:1): 也不创建新表。将任意一端的主键添加到另一端的表中(作为外键)。
- 原则:多端合并:要在many的那一端添加另外一端的主键作为外键
转换复杂属性:
- 复合属性: “扁平化”为多个列。
- E-R图:
name(first_name,last_name)
- 表 (Schema): …
first_name,last_name…
- E-R图:
- 多值属性: 必须为其创建新的表。
- E-R图:
instructor的{phone_number}
- 表 (Schema):
inst_phone(ID,phone_number)
- E-R图:
- 复合属性: “扁平化”为多个列。
转换专业化/泛化:
- 方法1 (面向高层):
为高层实体和每个低层实体都创建表。
- 表:
person(ID, name...)
- 表:
student(ID, tot_cred)
- 缺点: 获取完整的学生信息需要查询两个表。
- 表:
- 方法2 (面向低层):
只为每个低层实体创建表,表中包含继承的属性和自己的属性。
- 表:
student(ID, name..., tot_cred)
- 表:
instructor(ID, name..., salary)
- 缺点:
如果一个人既是学生又是员工(重叠),
name等信息会冗余存储。
- 表:
- 方法1 (面向高层):
为高层实体和每个低层实体都创建表。
如果您喜欢我的文章,可以考虑打赏以支持我继续创作.