创造新看点
首页 >> 科技咖 >> 正文

为什么我不喜欢数据库三范式

日期:2019-08-13 18:54:39 来源:互联网 编辑:小狐 阅读人数:736

插曲

最近,一个远房亲戚的小表弟准备选修专业

找到我问:

“哥,现在学数据库有没有前途阿?”

“当然有啊,前途大大的呢”

“那我现在开始学数据库,需要先从什么开始呢?”

“学课程的话,先了解下数据库三范式,SQL这些吧”

“SQL我大概知道,数据库三范式是什么?”

“阿...三范式就是表的主键...唯一性那些东西吧,...嗯,应该就是那些”

“什么是主键?”

“额.....表弟你不要再问了啦,好好去百度一下行不。”

“噢....”

挂完电话,我舒了口气,由于差点暴露自己已经不记得三范式了这个不争的事实,我悄悄打开了谷歌....

数据库的这个三范式的概念,相信大多数人都不会陌生,从懵懵懂懂的大学时代就已经普及到教材了(没记错的话应该在数据库概论这本教材里)

还记得那会刚开始找实习的时候,由于自己本事太小,连简历都不知道怎么写好,尤其是擅长技术的部分更是一片空白。

于是乎会找来隔壁几个学霸的简历来做参考,那会儿大家的简历上都会赫赫写着:

熟练掌握数据库三范式,精通数据库语言。

又或者是:

熟悉ER图制作工具,能实现满足三范式的数据库设计

一开始觉得数据库三范式确实是个好东西,以至于面试的时候技术官没有提问到三范式的细节,自己感到了惊讶和茫然。

随着工作经验逐渐见长,数据库范式理论在脑海里的强印象渐渐消除。我在想,要么是记忆的衰退,要么就是有些原则已经形成了本能的经验了。

那么,什么是数据库的范式?

三范式的定义

这里,不想花太多的篇幅去讨论理论性的东西,这些信息一抓一大把。我们就通过一些简单的例子来体会一下。

1. 第一范式

第一范式(1NF)数据库表的每一列都是不可分割的原子项

因此,应该拆分为:

2. 第二范式

以一个订单表为例,通常在上下单时会产生包含多个商品的订单,如下:

这里同样违反了第二范式的定义:

第二范式(2NF)每个表必须有且仅有一个数据元素为主键(Primary key)其他属性需完全依赖于主键

第二范式需建立在满足第一范式的基础之上

第二范式首先要求的是存在一个唯一的主键,在上面的表中,就必须将 订单号、商品号 作为一个联合的主键才能满足要求

那么对于第二点要求呢?其他属性是否依赖于这个主键?

在订单的场景中,我们可以认为这算是合理的,因为商品的价格甚至名称都可能会发生变化,而在每个订单中所看到的这些信息都应该是不变的。

谁也不希望看到自己已经支付的订单中的商品信息突然大降价.. 当然更重要的还是保持订单总价与商品单价记录的一致性。

因此这里的记录可以认为是商品信息在创建订单时的一个快照。

但是,对于下面的这一场景可能就不合适了:

商品所属的类别一般是固定的,也就是商品的类别属性仅仅与商品编号相关,即仅仅是依赖于主键的一部分。

这就违反了第二范式中“其他属性必须完全依赖于主键”的规则,因此需要将该属性分离到商品信息表中。

3. 第三范式

让我们回到一开始的用户表,如果在用户信息表中,同时补充一些城市的信息:

这样便违反了第三范式的定义:

第三范式(3NF)数据表中的每一列都和主键直接相关,而不能间接相关

同样,第三范式也需要建立在第二范式的基础之上

很明显,这里的城市人口、特色等属性都仅仅依赖于用户所在的城市,而不是用户,只能算间接的关系。

因此最好的做法是将城市相关的属性分离到一个城市信息表中。

为什么需要范式

那么范式的提出是为了解决什么问题?

第二范式,要求唯一的主键,且不存在对主键的部分依赖,希望消除表中存在冗余(多余)的列 比如订单表中的商品分类、详情信息,只需要由商品信息表存储一份即可。

第三范式,要求没有间接依赖于主键的列,即仍然是希望消除表中冗余的列 比如用户表中不需要存储额外的 其所在城市的人口、城市特点等信息。

很明显,这些范式大都是为了消除冗余而提出的,这有利于数据的一致性,当然也可以尽可能的减少存储成本。

PS:你懂得三范式,可以帮老板省钱,难怪简历上要写上..

为什么我不喜欢数据库三范式(图1)

除了本文中提到的三范式之外,实质上还有BCNF范式、第四、第五范式。

借助三范式的理念,你可以设计出很精炼的数据库表结构。然而现有的项目应用并不会完全遵循范式的理念,原因比如:

成本结构的变化,数据库范式是在20世纪提出的,当时的磁盘存储成本还很高。随着科技发展,数据存储的成本已经大幅度缩减,对于采用范式设计(规避冗余)带来的成本缩减收益已经不那么明显。 See the source image反范式设计

既然范式是为了消除冗余,那么反范式就是通过增加冗余、聚合的手段来提升性能。比如,为了提升查询的性能,在CMS的文章表中同时冗余的信息。

冗余的做法会牺牲一定的数据一致性,通常也是需要业务上进行权衡取舍。

当然,除了冗余(存储多份拷贝) 之外,还有另外的理念,即数据的聚合,或者叫嵌套。这种做法相当于是将多个字段(列)合并存储到数据库表的一个列中。

比如一条订单数据就可以同时包含许多信息:

...

...

这种灵活的结构几乎是 NoSQL的专利,比如MongoDB文档数据库就可以直接以内嵌数组、对象的形式来实现聚合式存储,这无疑带来了极大的灵活性。

而 MySQL 在5.2.7版本开始支持JSON结构化列,也进入了聚合式存储的队伍,与其对标的PostGreSQL 则是9.4版本就已经支持。

反范式的做法在互联网项目、开源产品中也比较常见,比如Discuz 的数据表设计中就存在许多的冗余列、聚合字段。

一方面,除了能获得性能的提升之外,数据压缩、高度灵活扩展(非结构化) 也是反范式设计能获得青睐的理由。

当然,这里并非一律反对数据库范式,理解范式仍然是做好数据库设计的一门基础,比如选择合适的主键、清晰的划分每一列属性等等。

在项目中仍然需要根据自身的业务特点在范式和反范式中找到平衡点(通常是两者的结合)。类似于架构设计中空间换时间的一些做法,这其中涉及到的各种取舍都是需要经过权衡的。

本文相关词条概念解析:

范式

设计范式(范式,数据库设计范式,数据库的设计范式)是符合某一种级别的关系模式的集合。构造数据库必须遵循一定的规则。在关系数据库中,这种规则就是范式。关系数据库中的关系必须满足一定的要求,即满足不同的范式。目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、第四范式(4NF)、第五范式(5NF)和第六范式(6NF)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。下面我们举例介绍第一范式(1NF)、第二范式(2NF)和第三范式(3NF)。

网友评论
  • 凤凰涅磐重
    什么是SQL注入,就是通过把SQL命令插入到Web表单提交或页面请求url的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
    2019-12-06 13:22 301
  • ujhggjhh
    看了题目描述,忍不住想打人
    2019-12-08 12:35 895
  • msilove
    数据库这门课为什么这么难学,该怎么学?
    2019-12-08 15:19 996