数据模型(中):键和规范化

上一篇:数据模型(上)_专治八阿哥的孟老师的博客-CSDN博客

3.键

键(或者码):键由一个或多个属性构成,通过键能有效的进行数据检索。键有很多种:候选键、主键、备用键、代理键、外键等。

候选键是一个或多个可以唯一标识实体实例的属性。如每个用户都有唯一的身份证号,则身份证号就可以是用户的候选键。有时需要通过多个属性才能检索到唯一的实例,我们习惯把多个属性组成的键称为复合键或组合键。候选键在物理模型中常被转化成唯一索引。一个实体可能拥有多个候选键,但我们只能选择其中一个作为主键,其余没有被选中的候选键称作备用键。

候选键有以下四个基本特征:

  1. 唯一性:候选键只能标识出一个实体;

  2. 强制性:候选键不能为空,每个实体必须能被一个特定的候选键标识;

  3. 非变异性:候选键的值不会被改变;

  4. 最小化:候选键中仅包含能唯一标识实体的属性,假设仅用两个属性就能标识出唯一实体,就不应该在候选键中包含第三个或更多其他属性。

在选取主键时,要考虑简洁性和隐私保护。当存在多个候选键时,一般选择属性最少或最短的充当主键。但当属性中包含敏感信息时(如身份证号、手机号),就不适合充当主键。因为主键有可能作为外键传递出去,容易造成隐私泄露。

在实际开发中,我们通常会使用系统自动生成的固定长度的唯一序列号来标识为实体,这种键称为代理键,代理键可以作为主键。代理键不具备任何业务含义,代理键是不可见的,它应该在幕后存在。比如用户表增加一个userId字段,在插入数据时由系统生生成id值,这个userId只在后台业务中标识用户,对用户本人来说没有任何意义。

使用代理键时,通常会配合自然键,自然键是在业务中唯一标识实体的方法,比如用户的身份证号。

外键:在一对多关系中,1的一端称为父实体,多的一端称为子实体。父实体中的主键被拷贝至子实体中,称为子实体的外键。

辅助键:非唯一的、经常被访问的、用于快速检索实体的一个或多个属性称为辅助键。

4.规范化

规范化是应用一组规则对事物进行整理的而过程,目前被大部分数据专家认可的规范化水平(范式)有如下六种:

  • 第一范式(First Normal Form,1NF);

  • 第二范式(Second Normal Form,2NF);

  • 第三范式(Third Normal Form,3NF);

  • 巴斯范式/鲍依斯-科得范式(Boyce/Codd Normal Form,BCNF);

  • 第四范式(Fourth Normal Form,4NF);

  • 第五范式(Fifth Normal Form,5NF);

每个级别的标准化都包括该级别之前低级别的规则,如果模型符合5NF,那么必定符合BCNF和4NF。通常情况下以前三个范式为主,需要用其余三个高级范式解决的特殊问题出现的概率非常低。

在了解具体的内容之前要明白几个术语:

1.函数依赖:简单点说,在数据库中有ABC三列,如果列A和列B的值可以确定列C的值,则C是函数依赖于(A,B)。比如通过学号和课程编号可以确定学生该课程的成绩,则成绩函数依赖于学号和课程编号。Y函数依赖于X记作X->Y。

下图中,设属性集包含ABC三个属性,ABC为候选键(主属性),属性D是非主属性,通过属性集里所有属性确定D,就是完全函数依赖;通过属性集里部分属性就能确定D,则是部分函数依赖(不完全函数依赖)。

2.平凡依赖:若X->Y,且Y是X的子集,就是平凡函数依赖。例如:在学生表(学号,姓名,年级)中,(学号,姓名)可以推出学号和姓名其中的任何一个,这就是平凡函数依赖。

3.非平凡依赖:若X->Y,但Y不是X的子集,就是非平凡函数依赖。在学生表(学号,姓名,年级)中,通过(学号,姓名)可以推出这个学生所在的年级,但年级不是(学号,姓名)的子集,这是非平凡函数依赖。

4.传递函数依赖:如果X->Y(Y不是X的子集),Y-/->X,Y->Z,Z是Y的子集,则称Z对X传递函数依赖。例如:学号->院系,院系->院长名,学号->院长名,但通过院长名不能反推出学号。

5.包含在候选键中的属性是主属性,不在任何一个候选键中的属性叫非主属性。

接下来介绍范式:

1NF:每个属性最多只有一个值依赖主键,每个属性是单值的,即列的原子性;下图中,部门职位一列,包含了部门和职位两个信息,不符合原子性,需要拆分。

2NF:满足第一范式基础上,提供一个完全的、唯一的依赖于主键的事实,即每条记录必须能被唯一的区分,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖);下图中技术部有两位叫李四的初级工程师,无法区分两条记录,需要添加工号作为主键,用以区分数据。

3NF:满足1NF和2NF基础上,每个非属性都必须直接依赖于主属性,而不依赖于其他非属性(在2NF基础上消除传递依赖)。下图中部门和职位名称与员工工号没有直接依赖关系,需要拆分成部门表和职位表。

接下来介绍其他三个高级范式(因为高级范式适用的场景比较少,所以下面的案例是为了展示范式内容,案例可能不符合真实业务逻辑):

BCNF:也叫修正3NF,在3NF基础上,任何主属性不能对主键子集依赖(在3NF基础上消除主属性对主键子集的依赖),避免主键中的某一列依赖主键中的其他列。在BCNF中,所有非主属性对于每一个候选键都是完全函数依赖,所有主属性对于不包含它的候选键也是完全函数依赖。

关于BCNF有个经典的仓库案例:

仓库管理关系表(仓库Id,管理员Id,物品Id,物品数量),仓库的存储规是:一个仓库只有一个管理员,且一个管理员只在一个仓库工作,仓库和物品是多对多关系,可以确认如下关系(->表示得到):

  • (仓库Id)->管理员Id

  • (管理员Id)->仓库Id

  • (仓库Id,物品Id)->物品数量和管理员Id;

  • (管理员Id,物品Id)->物品数量和仓库Id

可以看出 (仓库Id,物品Id)和 (管理员Id,物品Id)都可以作为候选键,表中的非主属性是商品数量,这是一个满足3NF的表。但是在主属性中,仓库Id和管理员Id存在依赖关系,所以不满足BCNF。

将表进行拆分(仓库Id,物品Id,物品数量)和(仓库Id,管理员Id),这样就满足了BCNF。

4NF:对于每个非平凡多值依赖,X->->Y(Y不属于X),X都含有候选键。多值关系是指在X->Y关系中,对于一个X存在多个Y与之对应。

4NF的示例很难找到恰当的业务场景,勉强举一个例子如下:角色和权限是多对多的关系,一个角色有多个权限,一个权限可以被多个角色拥有,用户角色权限表用来记录给用户授予的角色和权限,一个用户可以对应多个角色,并拥有该角色对应的权限。可以看到用户和角色也是多对多关系,(用户,角色,权限)就是联合主键,可以看到候选码之间无函数依赖,符合BCNF。

在用户角色权限表中,给定一组(用户,角色)能得到一组权限,即(用户,角色)->->(权限),但(用户,角色)不是候选键,所以它不符合4NF,进行拆分:

5NF:R的依赖均由R候选码所隐含,这是指在连接时,所连接的属性均为候选码;5NF通俗的说,就是将表尽量分割成小的表,减少数据的冗余,5NF又叫完美范式。很难找到需要设计成4NF又不满足5NF的案例,故而此处简单举一个例子表述一下分割成小表的含义,如下图所示,员工表和部门表,这是一个非常简单的模型,符合3NF,因为它的主键就是编号一列,没有多对多关系,所以不会违反BCNF和4NF。

但是在上面的例子里,员工表中的部门编号不是候选码,但与部门表关联时,需要用到部门编号,所以不符合5NF。将表进行改造:

拆分出一张员工部门的关系表,候选码是(工号,部门),此时三张表关联时,比如查到员工的部门名称,需要用员工表的(工号)、员工部门表的(工号,部门),部门表的(部门编号),所连接的属性都是候选码,就满足了5NF。

我们会发现5NF将数据库中的表拆分的非常小,关系变得更加复杂,在操作时需要连接更多的表才能得到数据。但5NF的扩展性更高,5NF能兼容各种对应关系,如1对多、多对多,比如一个员工可以在多个部门兼职,那么对于5NF来说,只是在关系表中添加一条数据罢了,而3NF则需要重新修改模型。

实际开发中主要考虑前三个范式,范式层级越高,数据维护操作的复杂性也就越高,为了保证开发效率,我们也会在开发时使用一些反范式的操作,下一节将给大家分享反范式相关的内容。

参考资料:

​    《数据建模》[美]Steve Hoberman 著 丁永军 译

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专治八阿哥的孟老师

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值