seegongsik
数据

什么是数据库规范化

假设每来一笔订单,都在同一张表里把顾客的姓名和电话一起写上。同一位顾客下十次单,同样的姓名和号码就会在十行里原样重复。这位顾客一换电话号码,十行都得改,漏掉一行,那一行就还留着旧号码。麻烦的根源,在于同样的信息写了不止一遍。为了让重复的信息只放在一个地方而把表拆开,这就是规范化。

01

同样的信息一写再写

上一课,我们用公共列把两张表连起来发问。这一课反过来看:表当初为什么要那样拆开。假设每接一笔订单,就在一张表里添一行,还把顾客的姓名和电话也写进去。
同一位顾客多次下单,这位顾客的姓名和号码就会一行行原样重写。下面的表里,敏秀下了三笔订单,就出现了三次。

订单
顾客
电话
A-01
敏秀
010-1111
A-02
智英
010-2222
A-03
敏秀
010-1111
A-04
蓝天
010-3333
A-05
敏秀
010-1111
A-06
智英
010-2222
点一个顾客姓名找出重复

点一个顾客姓名。这位顾客的信息在几行里写得一模一样,一眼就能看出来。

同样的信息一行行刻在那里。白占地方是一个问题,更大的麻烦出在修改的时候。敏秀换了电话号码,就得把写着敏秀的行全部找出来改掉;哪怕漏掉一行,同一个人就有了两个号码,光看表也分不清哪个对。
麻烦还不止这一个。还没下过单的新顾客没有可写的行,连名字都登记不了;把蓝天唯一的一笔订单删掉,蓝天的电话号码也跟着没了。修改、插入、删除时出现的这些不一致,分别叫更新异常、插入异常和删除异常。

02

把重复的部分拿出来分开

解决办法比想象的简单:把重复的部分拿出来,单独建一张表。顾客的姓名和电话不再每笔订单都写,而是写在只放顾客的顾客表里,每人一行,只写一次。
这样,订单表里整块顾客信息都去掉了,只剩下订单号这类只属于订单本身的列。说到底,就是弄清每条信息属于谁,再把它放到该放的地方。

订单表
订单
顾客
电话
A-01
敏秀
010-1111
A-02
智英
010-2222
A-03
敏秀
010-1111
A-04
蓝天
010-3333
A-05
敏秀
010-1111
A-06
智英
010-2222
点拆分把重复剥出来

点拆分。原本重复的顾客信息离开订单表,在顾客表里每人一行聚到一起。

顾客信息聚到了一处。现在敏秀换号码,只改顾客表里那一行就行。不管有一百笔还是一千笔订单,要改的都只有一行,既不会漏,也不会一个人有两个号码。新顾客没下单也能登记进顾客表,删掉订单,顾客信息也还在。
可又冒出一个担心:顾客信息已经从订单表里拿走了,哪笔订单是谁的,怎么知道呢?

03

用公共列重新连上

这时就用得上上一课的连接了。拆表时不能一拆了之,要在两张表里留下同一个列。顾客表里放顾客编号、姓名和电话,订单表里不写姓名,只写顾客编号。
这个顾客编号,就是把两张表系在一起的线。看订单表里的编号,到顾客表里找相同的编号,马上就知道这笔订单是谁的。

一个编号就把两张表连起来了。信息虽然只写在一处,顺着线走,随时都能拼到一起看。重复没了,要改的地方缩到一处,需要的信息用连接照样能全部凑齐。
这就是规范化的核心。实际工作中,这个想法被整理成一级级的规则,叫作范式:从每个格子只放一个值开始,一步步把表理顺。不过,好事做过头也会出问题。表拆得太细,会怎样?

04

拆得太细,也会故意合回去

要是只因为讨厌重复就一味拆细,表会越来越多:地址放地址表,会员等级放等级表,每件小事都单独设一张表。
这样一来,想把一位顾客看清楚,就得把三四张表连接起来。连接并不是没有代价的,要连的表越多,答案出来得越慢。重复是少了,读取却变慢了。

订单表
顾客表
地址表
等级表
要接的次数多
重复无
没有重复,但看一个人要接四张表,所以慢。

在分得细和故意合并之间来回点。分得越细,要连的表越多;合并后会多出一点重复,但一次就能看全。

拆和合,彼此有得有失。拆得细,没有重复,干净利落,可每次查看都要连表,所以慢。因此,总是一起读取的信息,有时会故意合到一张表里,这叫反规范化。
这也有代价:同样的信息又出现在好几处,每次变动都得有办法让这些副本保持一致。写入频繁的地方偏向规范化,读取远多于写入的地方偏向反规范化,就这样取得平衡。

05

小结

归纳起来是这样:在一张表里反复写同样的信息,既浪费地方,修改、插入、删除时信息还会对不上。所以把重复的部分拿出来,分到单独一张表,再用公共列重新连上。
每条信息只放一处,需要时用连接拼起来看。拆得太细而变慢时,也会故意合并,把握好这个平衡,也是规范化的一部分。

依次点要点回顾一下

依次点要点回顾一下。(重复是浪费和不一致 → 把重复拿出来分开 → 用公共列连上 → 拆得太细就故意合并)

现在,你有了判断表该怎么拆、拆到哪里为止的依据。每条信息只放一处,修改时出错的机会就少了。
不过,有时得一次同时修改好几张表。比如记下订单的同时减少库存,要是两件事只做了一件就停下,表与表之间就对不上了。怎样把几项修改捆成一个整体,要么全部完成,要么全部不做,下一课讲数据库事务时会说明。

一句话总结规范化是这样一种整理:把一张表里反复出现的信息拿出来,分到单独一张表,再用公共列重新连上。不在每笔订单上写顾客姓名,而是在顾客表里每人只写一次,订单表里只留顾客编号。这样电话号码变了,只改顾客表里一行就行;没下过单的顾客也能登记;删掉订单,顾客信息也还在。需要的信息,随时可以用连接重新凑齐。不过拆得太细,每次查看都得连好几张表,可能变慢。这时会把总是一起读取的信息故意合到一张表里,这叫反规范化。把重复拿出来分开、用关系连上,过了头再合回去,规范化的要点就在这个平衡。
← 数据
如果有帮助,请支持我们