数据库设计三大范式
为什么要遵循三大范式去设计数据库?
比如说在我们的现实世界中,要去建造一栋房子,如果盖一间茅屋或一间简易平房,会有人花钱去请人设计房屋图样吗?毫无疑问,没有人会去请。 但是如果是房地产开发商开发一个楼盘,修建多幢楼的居住小区,他会去请人设计图纸吗?答案是肯定的。不但开发商会考虑去设计图样,甚至很多专业的购房者也会在看房的是要求开发出示设计图样。
同理,在我们的实际开发中,如果系统的数据存储量较大,设计的表比较多,表和表之间的关系比较复杂,就需要首先考虑规范化的数据库设计,然后再进行具体的创建库 、表的工作。为了设计结构合理的数据库,必须遵循一定的规则,在关系数据库中这种规则就称为范式,范式是符合某一种设计要求的总结。
1、第一范式(1NF)
第一范式的目的是确保每列的原子性。如果每列(或者每个属性值)都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式。(个人理解就是无重复列或列不可分)。
需要注意的是:第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到"地址"这个属性,本来直接将"地址"属性设计成一个数据库表的字段就行,但如果系统经常会访问"地址"属性中的"城市"部分,那么就非要将"地址"这个属性进行重新拆分为省分、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才满足了数据的第一范式,如下表二所示。
比如说
用户表一(未拆分) | ||||
编号 | 姓名 | 性别 | 年龄 | 地址 |
1001 | 张三 | 男 | 20 | xxx省xxx市xxx区xxx路xxx号 |
1002 | 李丽 | 女 | 23 | yyy省yyy市yyy区yyy路yyy号 |
1003 | 风清扬 | 男 | 56 | ooo省ooo市ooo区ooo路ooo号 |
用户表二(拆分后) | ||||||
编号 | 姓名 | 性别 | 年龄 | 省份 | 城市 | 详址 |
1001 | 张三 | 男 | 20 | xxx省 | xxx市 | xxx区xxx路xxx号 |
1002 | 李丽 | 女 | 23 | yyy省 | yyy市 | yyy区yyy路yyy号 |
1003 | 风清扬 | 男 | 56 | ooo省 | ooo市 | ooo区ooo路ooo号 |
2、第二范式(2NF)
第二范式在第一范式的基础上更进一层,其目标是确保表中的每一列都和主键相关。如果一个关系满足第一范式(1NF),并且除了主键以外的其他列都全部依赖于该主键,则满足第二范式(2NF)。
通俗理解就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如说要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
订单信息表 | ||||||||
订单编号 | 商品编号 | 商品名称 | 数量 | 单位 | 价格 | 客户 | 所属单位 | 联系方式 |
|
|
|
|
|
|
|
|
这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键,这样就在该表商品名、单位、商品价格等信息不与主键相关,而仅仅是与商品编号相关。所以在这里就违反了第二范式的设计原则。
而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中就完美了。如下所示。
订单信息表 | |||
订单编号 | 客户 | 所属单位 | 联系方式 |
订单项目表 | ||
订单编号 | 商品编号 | 数量 |
商品信息表 | |||
商品编号 | 商品名称 | 单位 | 商品价格 |
3、第三范式(3NF)
第三范式(3NF)在第二范式的基础上更进一层,第三范式的目标是确保每列都和主键列直接相关,而不是间接相关,如果一个关系满足第二范式(2NF),并且除了主键外的其他列都只能依赖于主键列,列和列之间不存在相互依赖关系,满足第三范式(3NF)。
通俗理解:不能存在传递依赖。 除了主键外,其他字段必须依赖主键
例如:
爸爸 | 儿子 | 儿子的手机 | 儿子的电脑 |
|
|
|
因为上表的手机和电脑属于儿子,因此不符合第三范式,对上表进行拆分
爸爸信息表 | |
爸爸 | 儿子 |
儿子信息表 | ||
儿子 | 儿子的手机 | 儿子的电脑 |
总结
数据库设计规范化能让我们更好地适应变化,使你能够改变业务规则、需求和数据而不需要重新构造整个系统。