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

插曲

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

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

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

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

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

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

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

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

三范式的定义

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

1. 第一范式

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

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

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

因此,应该拆分为:

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

2. 第二范式

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

o1g1洗衣液23
o1g2吹风机125
o1g3蚕豆5
o2g9被子302
o2g8枕头69

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

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

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

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

o1g1洗衣液23家居
o1g2吹风机125电器
o1g3蚕豆5食品
o2g9被子302家居
o2g8枕头69家居

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

3. 第三范式

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

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

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

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

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

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

为什么需要范式

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

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

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

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

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

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

640?wx_fmt=png

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

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

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

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

640?wx_fmt=png

反范式设计

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

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

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

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

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

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314451.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬货 - 技术人也能轻松玩转公众号?正确姿势竟然是...

最近在知乎上看到关于「公众号是否有“前”途」的相关问题... 问题下面有些精华回答~微信公众号还有“前”途吗? - 知乎https://www.zhihu.com/question/324575670很好的问题!作为一个技术人,我决定将此问题和自身情况结合起来,于…

你必须知道的Dockerfile

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。本文预计阅读时间为5分钟。01—关于Dockerfile在Docker中创建镜像最常用的方式,就是使用Dockerfile。Dockerfile是一个Docker镜像的描述文件,我…

RabbitMQ 死信/死信队列

一、RabbitMQ 死信/死信队列1、DLXDead Letter Exchange 的缩写DLX(Dead Letter Exchanges)死信交换,死信队列本身也是一个普通的消息队列,在创建队列的时候,通过设置一些关键参数,可以将一个普通的消息队列…

centos7 rabbitmq安装/配置

一、RabbitMQ简单介绍RabbitMQ就是当前最主流的消息中间件之一。RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支…

Hyper-V + CentOS7 安装视频教程

一、前言本文使用图文视频的方式展示安装Centos7,【喜欢看视频学习的童靴请拖至文尾观看视频】二、虚拟机配置指定虚拟机名称&安装位置选择虚拟机代数 第一代虚拟机(例如Server 2008等平台技术,支持Vista、Win7) 第二代虚拟机…

程序员修神之路--用NOSql给高并发系统加速

领取福利记得长按,领取技术书籍哦随着互联网大潮的到来,越来越多网站,应用系统需要海量数据的支撑,高并发、低延迟、高可用、高扩展等要求在传统的关系型数据库中已经得不到满足,或者说关系型数据库应对这些需求已经显…

限时团购,6.5折:《C# 7.0 核心技术指南》

大家好,经过近两年的翻译,《C# 7.0 核心技术指南》终于和大家见面了。全书由 ThoughtWorks 高级咨询师,资深 .NET 专家刘夏翻译。作为一本第七次再版的图书,此次翻译对书中的字句进行了重新整理。期间和图书的原作者 Joe Albahari…

Azure 命令行工具大混战,都是什么,该选哪个?

点击上方蓝字关注“汪宇杰博客”导语最近在学习 Azure 的命令行玩法,发现官方有不止一种命令行工具,容易对新手产生混淆,本文将介绍各种工具都是干啥的,以及如何选择。目前,微软官方有3个Azure命令行工具,分…

揭秘鸿蒙生态背后的DevOps实践

(图片来源于网络)8月9日,华为发布了鸿蒙操作系统,在发布会上我们看到了鸿蒙系统的研发历程:2017年,鸿蒙内核1.0完成技术验证;2018年,鸿蒙内核2.0用于终端TEE;2019年&…

AT3557 Four Coloring 切比雪夫距离 + 四色构造

传送门 由于曼哈顿距离在图上显示的是一个棱形,并不是很好看,所以我们将其旋转454545,转换成切比雪夫距离,这样就变成了一个正方形,正方形内部的点距离都不超过ddd,此时可以将正方形内部的点看成一个整体&a…

SonarQube系列一、Linux安装与部署

来源:https://www.cnblogs.com/7tiny/p/11269774.html【前言】随着项目团队规模日益壮大,项目代码量也越来越多。且不说团队成员编码水平层次不齐,即便是老手,也难免因为代码量的增加和任务的繁重而忽略代码的质量,最终…

P2906 [USACO08OPEN]Cow Neighborhoods G 切比雪夫距离 + 并查集 + set

传送门 考虑将曼哈顿距离转换成切比雪夫距离,这样问题就变成了max(∣x1−x2∣,∣y1−y2∣)≤dmax(|x_1-x_2|,|y_1-y_2|)\le dmax(∣x1​−x2​∣,∣y1​−y2​∣)≤d,这个式子就很好看了,我们首先按照(x,y)(x,y)(x,y)排序,让后我…

2018-2019 ACM-ICPC, Asia Shenyang Regional Contest E. The Kouga Ninja Scrolls 切比雪夫距离 +线段树

传送门 将曼哈顿距离转换成切比雪夫距离,现在就是求max(∣x1−x2∣,∣y1−y2∣)max(|x_1-x_2|,|y_1-y_2|)max(∣x1​−x2​∣,∣y1​−y2​∣),显然我们可以将x,yx,yx,y分开考虑,下面以xxx为例。 考虑一段区间内不同门派的最大值和最小值&am…

ASP.NET Core 框架本质学习

本文作为学习过程中的一个记录。学习文章地址:https://www.cnblogs.com/artech/p/inside-asp-net-core-framework.html一. ASP.NET Core 框架上的 Hello World程序public class Program{public static void Main()> new WebHostBuilder() .UseKestrel() …

基于C#实现的轻量级多线程队列

工作中我们经常会遇到一些一些功能需要实现造作日志,数据修改日志,对于这种业务需求如果我们以同步的方式实现,难免会影响到系统的性能。如下我列出集中解决方案。使用Thread异步处理。使用线程池或Task异步处理。以上两种方案确实能解决我们…

【活动】厦门.NET俱乐部 省上云开发者专场

十年磨一剑,厦门.NET俱乐部诚挚邀请您相约软件园二期创驿站,参加云重启|厦门.NET俱乐部省上云开发者专场。活动干货满满,更有精美礼品,厦门.NET俱乐部期待与您“厦门论剑”。详情请点击图片或直接阅读原文报名

腾讯物联TencentOS tiny上云初探

2017年中旬曾写过一篇关于物联网平台的文章《微软最完善,百度最“小气” 看微软阿里百度三大物联网云平台对比》。现在已经过去两年了,物联网的格局又发生了不少的变化。不过针对腾讯来说,其物联网平台发轫的时间绝不算晚,基本就是…

ASP.NET Core on K8S深入学习(3-2)DaemonSet与Job

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。上一篇《3-1 Deployment》中介绍了Deployment,它可以满足我们大部分时候的应用部署(无状态服务类容器),但是针对一些特…

Asp.Net Core WebAPI+PostgreSQL部署在Docker中

PostgreSQL是一个功能强大的开源数据库系统。它支持了大多数的SQL:2008标准的数据类型,包括整型、数值值、布尔型、字节型、字符型、日期型、时间间隔型和时间型,它也支持存储二进制的大对像,包括图片、声音和视频。PostgreSQL对很多高级开发…

博客园升级有感一点建议

实践出真知这几天在园子里面最热闹的事情各位都知道吧?没错,我说的就是博客园升级事件,有不熟悉的朋友吗,没关系,我给你搬运好了,请回顾一下Powered by .NET Core 系列博文:【故障公告】发布 .N…