插曲

最近,一个远房亲戚的小表弟准备选修专业
找到我问:

"哥,现在学数据库有没有前途阿?""当然有啊,前途大大的呢""那我现在开始学数据库,需要先从什么开始呢?""学课程的话,先了解下数据库三范式,SQL这些吧""SQL我大概知道,数据库三范式是什么?""阿...三范式就是表的主键...唯一性那些东西吧,...嗯,应该就是那些""什么是主键?""额.....表弟你不要再问了啦,好好去百度一下行不。""噢...."

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

数据库的这个三范式的概念,相信大多数人都不会陌生,从懵懵懂懂的大学时代就已经普及到教材了(没记错的话应该在数据库系统概论这本教材里)。
还记得那会刚开始找实习的时候,由于自己本事太小,连简历都不知道怎么写好,尤其是擅长技术的部分更是一片空白。
于是乎会找来隔壁几个学霸的简历来做参考,那会儿大家的简历上都会赫赫写着:

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

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

一开始觉得数据库三范式确实是个好东西,以至于面试的时候技术官没有提问到三范式的细节,自己感到了惊讶和茫然。
随着工作经验逐渐见长,数据库范式理论在脑海里的强印象渐渐消除。我在想,要么是记忆的衰退,要么就是有些原则已经形成了本能的经验了。

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

三范式的定义

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

1. 第一范式

假设有一张用户信息表,上面除了用户编号、姓名之外,还会记录地址信息:

0001 张三 广东省,深圳市
0002 李四 海南省,海口市

在这里面,地址信息一栏就是不符合第一范式(1NF)的:
第一范式(1NF):数据库表的每一列都是不可分割的原子项

因此,应该拆分为:

0001 张三 广东省 深圳市
0002 李四 海南省 海口市

2. 第二范式

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

o1 g1 洗衣液 23
o1 g2 吹风机 125
o1 g3 蚕豆 5
o2 g9 被子 302
o2 g8 枕头 69

这里同样违反了第二范式的定义:
第二范式(2NF):每个表必须有且仅有一个数据元素为主键(Primary key),其他属性需完全依赖于主键

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

第二范式首先要求的是存在一个唯一的主键,在上面的表中,就必须将 订单号、商品号 作为一个联合的主键才能满足要求
那么对于第二点要求呢?其他属性是否依赖于这个主键?
在订单的场景中,我们可以认为这算是合理的,因为商品的价格甚至名称都可能会发生变化,而在每个订单中所看到的这些信息都应该是不变的,
谁也不希望看到自己已经支付的订单中的商品信息突然大降价.. 当然更重要的还是保持订单总价与商品单价记录的一致性。
因此这里的记录可以认为是商品信息在创建订单时的一个快照。

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

o1 g1 洗衣液 23 家居
o1 g2 吹风机 125 电器
o1 g3 蚕豆 5 食品
o2 g9 被子 302 家居
o2 g8 枕头 69 家居

商品所属的类别一般是固定的,也就是商品的类别属性仅仅与商品编号相关,即仅仅是依赖于主键的一部分。
这就违反了第二范式中"其他属性必须完全依赖于主键"的规则,因此需要将该属性分离到商品信息表中。

3. 第三范式

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

0001 张三 深圳市 科技、创新 1300W
0002 李四 海口市 旅游、观光 230W

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

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

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

很明显,这里的城市人口、特色等属性都仅仅依赖于用户所在的城市,而不是用户,只能算间接的关系。
因此最好的做法是将城市相关的属性分离到一个城市信息表中。

为什么需要范式

数据库范式为数据库的设计、开发提供了一个可参考的典范,在许多教学材料中也是作为关键的课程内容。
那么范式的提出是为了解决什么问题?

  • 第一范式,要求将列尽可能最小的分割,希望消除某个列存储多个值的冗余的行为
    比如用户表中的地址信息,拆分为省、市这种明确的字段,可以按独立的字段检索、查询

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

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

很明显,这些范式大都是为了消除冗余而提出的,即尽可能的减少存储成本。

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

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

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

  1. 性能原因,没有任何冗余的表设计会产生更多的查询行为,这意味着会产生更多次的数据库IO操作。在一些实时交互的系统中,可能会慢得让人难以忍受。
    当然,你可以使用数据库的 连接(join) 操作,而事实上数据库提供 join 也就是为了来缓解这种问题。但一旦用到了分库分表方案的面前,这个问题就会非常的棘手。

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

反范式设计

既然范式是为了消除冗余,那么反范式就是通过增加冗余、聚合的手段来提升性能。比如,为了提升查询的性能,在CMS的文章表中同时冗余作者的信息。
当然,除了冗余(存储多份拷贝) 之外,还有另外的理念,即数据的聚合,或者叫嵌套。这种做法相当于是将多个字段(列)合并存储到数据库表的一个列中。

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

这种灵活的结构几乎是 NoSQL的专利,比如MongoDB文档数据库就可以直接以内嵌数组、对象的形式来实现聚合式存储,这无疑带来了极大的灵活性。
而 MySQL 在5.2.7版本开始支持JSON结构化列,也进入了聚合式存储的队伍,与其对标的PostGreSQL 则是9.4版本就已经支持。

反范式的设计在互联网项目、开源产品中也非常之常见,比如大名鼎鼎的Discuz 的数据表设计中就存在许多的冗余列、聚合字段。
一方面,除了能获得性能的提升之外,数据压缩、高度灵活扩展(非结构化) 也是反范式设计能获得青睐的理由。

当然,这里并非一律反对数据库范式,理解范式仍然是做好数据库设计的一门基础,比如选择合适的主键、清晰的划分每一列属性等等。
在项目中仍然需要根据自身的业务特点在范式和反范式中找到平衡点(通常是两者的结合)。类似于架构设计中空间换时间的一些做法,这其中涉及到的各种取舍都是需要经过权衡的。

也可以说这是一门艺术,因为没有标准答案...

为什么我不喜欢数据库三范式相关推荐

  1. python学习笔记 day44 数据库三范式

    参考自 https://www.cnblogs.com/wangfengming/articles/7929118.html 1. 数据库三范式概念: 为了建立减少冗余,结构合理的数据库,涉及数据库时 ...

  2. MySQL笔记(七)数据库三范式

    这是我在学习Mysql之路上做的笔记,今天将它粘出来.这一篇主要是数据库三范式.有错误的欢迎大家指出... 数据库三范式 (1)第一范式(1NF): 定义:每一列都是不可分割的原子数据项(强调的是列的 ...

  3. 数据库三范式 无重复列 完全依赖主键 属性不依赖非主属性

    参考:http://www.cnblogs.com/xrq730/p/5100442.html 细说数据库三范式 2.1 第一范式(1NF)无重复的列,保证每列的原子性,即每一列的各个属性值之间不能有 ...

  4. 三句话归纳数据库三范式

    数据库三范式,网友已经总结n多了,这里不再赘述. 其实,归纳起来,就三句话: 一:行不可再分 二:列不可再分 三:列不可重复

  5. 从数据库三范式角度分析一对多、多对多和一对一关系

    文章目录 前言 一.三范式的目的 二.三范式及其对应关系 1.第一范式 2.第二范式 3.第三范式 4.一对一关系 总结 前言 几乎绝大多数项目的最终目的都是通过操作数据库来实现的,所以,操作数据库的 ...

  6. 数据库三范式通俗理解 -数据库三范式官方定义

    数据库三范式 官方定义 第一范式(1NF):数据库表中的字段都是单一属性的,不可再分. 第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖 第三范式(3NF):在第二范式的 ...

  7. MySql——数据库三范式

    用于自己学习时的简单解释 数据库三范式:是数据库的设计原则,主要目的是为了避免数据冗余. 数据库的设计应当遵循三范式 第一范式:任何一张表都应该有主键,每一个字段必须具有原子性不可再分 第二范式:在第 ...

  8. 如何在数据库三范式的基础上进行数据库冗余设计

    数据库设计过程中不仅要考虑遵循第三范式,还要考虑是否冗余 很多数据库设计书籍都强调数据库设计三范式,而三范式的一个重要工作就是消除冗余,可以消除冗余在大多数情况下是正确的.当在实际的业务模型中,处理复 ...

  9. mysql三范式和反三范式_数据库三范式和反三范式

    要说数据库什么最抽象,我觉得就是这个三范式,不是很好理解,但是表在设计的时候又必须要知道这么一个规则. 首先使用最简洁的话说说这三范式: 第一范式(1NF:The First Normal Form) ...

最新文章

  1. R语言使用moments包计算偏度(Skewness)和峰度(Kurtosis)实战:计算偏度(Skewness)和峰度(Kurtosis)、确定样本数据是否具有与正态分布匹配的偏度和峰度(假设检验)
  2. SQL系列ROLLUP关键字
  3. python与excel的应用-Python 3 读取和存储Excel数据(应用到接口测试)
  4. ANSI C标准函数库
  5. SAE帮助「海底小纵队学英语」全面拥抱Serverless
  6. SQL触发器demo
  7. 薛定谔的猫——.NET 4.1 中的新基类,开源Preview中
  8. windows安装mysql 5.7
  9. 华为背锅?微博大V质疑华为P30 Pro拍月亮造假 公司称误导观众已开除
  10. 如何生成MD5哈希?
  11. Android MultiAutocompleteTextView
  12. VC6.0 2 VC2008 移植 中多字节字符集和Unicode之间的互换
  13. BackTrack 4 新功能
  14. 西门子Step7安装和入门初步
  15. TexWorks 拼写检查
  16. win10右键一直转圈_windows10为何鼠标右键一点桌面就一直转圈?
  17. 相机参数(焦距)初始化对三维重建过程的影响
  18. Spring Boot 项目 启动 端口经常被占用 彻底解决方案
  19. 西游记中泾河龙王泄露天机惨遭砍头,而袁守诚为何安然无恙
  20. 多签名基础——General forking lemma(分叉引理)

热门文章

  1. win10任务栏和开始菜单_如何将网站固定到Windows 10任务栏或开始菜单
  2. php的几种运行模式CLI、CGI、FastCGI、mod_php
  3. Android开发之动画(转)
  4. Java网页开发中model实现Serializable接口的原因
  5. ASP.NET : Kerberos网络认证过程
  6. 【招聘(北京武汉)】北京高远华信科技 .NET 高级工程师
  7. .NET大会2021参会笔记
  8. 福利好礼现金大奖等你来→首届 .NET Conf China Hackathon 火热报名中!
  9. ASP.Net Core Web API 如何返回 File。
  10. 为啥 .NET 自带的 JsonSerializer 无法序列化 Field ?