00:00
好,那我们在讲完具体的这个范式之后啊,咱们下边呢,给大家举一个这个实战的案例,哎,那么大家呢,去体会一下,在我们实战当中的话呢,我们该如何应用咱们的范式,包括反范式化啊,OK啊,那这里呢,我们以一个叫呃,商超当中的进货系统里边这个进货单表呢,给大家去举这个例子啊,那么这个进货单表呢,我就摆在这儿了啊实际上呢,这个表中的这个数据量呢,是非常庞大的。啊,就是很多行的数据啊,那打开这个表啊,查询的时候呢,花的这个时间呢,发现也很多啊,那效率呢是比较低的,那针对这个表呢,我们需要呢,来进行一些改造,那么打眼一看这个表呢,大家其实你就会发现呢,是不是会有一些这个冗余的一些数据和字段在里边,是吧?啊那这时候的话呢,就有必要呢,对它进行改造,改造的这个标准是什么呢?就是我们前面讲过的这个范式。啊,就是我们讲过这个范式。好,这里边你看有一句话啊,在实际的工作场景当中,由于这种表的结构的设计的不合理,导致我们数据重复的现象啊,其实并不少见。
01:02
诶,往往呢,是系统虽然能够运行,承载能力呢却很差,稍微的有点流量就会出现内存不足,CPU飙升的这个情况,甚至呢,导致我们整个项目呢失败。啊,这个呢,大家你注意啊,不像咱们平时大家上这个小学,甚至说你上这个呃中学啊大学一样啊,我们考试的时候呢,这道题20分啊,你完全做出来了啊,过程一点问题没有好20分过了,那你这个呢,我们中间过程没问题,后者结果呢,没算出来好15分,这个题一点不会零分,对吧,你在工作当中的话呢,是不是没有人给你去针对任何一个需求,或者一个表的一个设计给你去打分吧。啊,你说我们这个表设计出来了,这个是不是完美的呢?啊,是不是精准的呢?然后给我打个分吧,首先呢,在实际工作当中,咱们就不像说考试的时候,一道题它是有一个完美的一个解决方案的啊,就是那样精准的一个做法啊,这个20分全给你了是吧,那在实际工作当中可能就没有完美之说。啊,首先他没有完美之说,那其次的话呢,是不是也没有人去衡量,你说你这个呢,是不是完美的,你说项目经理或组长去给你做这个事儿,这不太靠谱啊,他都给你审一遍的话呢,然后呢,要改是你还行,那改也不是你他自己去改,那要你干啥呢。
02:12
对吧,所以呢,从这个呃,这个整个项目经理的角度来讲,他更多的看的是诶大家每个人分配相应的功能模块,然后呢,我们该测试呢去测试,然后呢,看看是不是通过测试呢,诶发现有bug了,有bug呢我们就去改bug,但是呢,呃,比如说这个表呢,你设计的可能并不好,但是呢没有影响使用。啊,就是测试的时候也没测试出来,但是随着我们这个数据量的不断的去增加,然后后续的话呢,我们发现这样的问题了,呃,然后翻回来去看,发现我们这个世界的并不完美。诶,这个呢,在实际生活当中啊,或实际生产环境当中,我们说呢,呃,绝大部分的场景呢,实际上我们设计的都不完美啊,那我们就需要呢,要说兵来将挡水的土掩啊,那后期呢,发现这样问题的话,我们来进行这个改造。好,那么改造的话呢,我们就遵循这三个范式啊,从第一到高级意思来讲解,首先呢,来看这个一范式,一范式的话呢,就是保证我们这里边儿每一个字段啊,它得是一个原子性的啊,不可再拆分的了。
03:09
那我们从前往后这样去走,你看哪个呢,有可能会拆分,诶这块呢,是不是走到我们的叫property这样一个属性上了,这个属性的话呢,你发现诶它是一袋啊有六包啊,一盒呢有十支,那我们其实呢,是不是可以考虑把它这个单位和前面这个数量呢,给它拆分出来啊。啊,这个呢,就是我们,呃,从这个依法式的角度呢,去做了个处理,我呢就拆分成啊叫specification和这个。啊,一个叫单位啊,一个呢叫我们这个具体的规格,诶这样拆开它啊,一范式呢,也是最容易理解的啊别的呢,没什么问题,好就这样了,然后接下来的话呢,我们要考虑一个二范式,那首先呢,你得清楚这个二范式的这个规则说,在满足这一范式的基础上呢,还需要满足数据表里边每一条数据记录啊,都得是可唯一标识的。那既然可以唯一标识,我们需要呢,是不是是不是就是定义这个表中的这个主见了呀,啊定义主见好,那接着的话,你再有主见以后呢,我们再看这个完全依赖的问题,好那我们来看一下这个主键应该呃定义哪个啊呃,那此时的话呢,我们就需要关注于这样一个表的字段了啊一般呢,我们看到像这种单号啊,什么编号啊,诶这些呢,咱们是不是都会敏感一些,因为天然的就想把它们是不是当成这种主见,对吧。
04:21
好,首先呢,我们来看这个单号啊,这个单号的话呢,呃,001啊002啊003呀,是吧?呃,单号后边呢,有这个叫供应商的编号。嗯,供应商的编号,诶其实你这样想啊,他俩呢,是不是有这种互相的这种依赖关系,诶我们一旦确定这个,呃,你进货的这个单号的话呢,其实你这个,呃,进货这个单号对应的供应商编号是谁,其实通常话呢,是不是就也确定下来了。对吧,你看我们这001啊,这个是一啊,这个也是一啊,这个003的话也是一啊,相当于这块呢,就依赖于它了,那既然这样我们就没有必要呢,是不是把它俩和一起构成主线了,对吧。呃,那供应商的编号确定了,供应商的名称是不是也确定了,诶所以这块呢,诶这都依赖于他就行,然后仓库呢,用的是什么,诶那个单号呢是什么,然后你这个仓库用的是哪个,这个也就确定了,所以呢,这几个呢都依赖于他。
05:08
然后呢,后边呢,就是你这个单号下边呢,是不是进货的具体一些东西了啊嗯,你看我们这里边儿都是001,都是001的话呢,呃,我们说这个条形码能完全由他来决定吗。啊,似乎呢,不能说一个匹配一个了啊,因为你看这都是001的情况下,你这是不是有001还有002,相当于你进了两个不同的这个产品对吧?诶两个不同这个产品,呃,你要是光拿它当主件的话,你这不就意味着有这个重复的这个主键值了吗?呃,那这个条码我们把它呢也考虑再来考虑进来。诶一看其实还确实可以对吧,你在这个单号的情况下呢,我们具体的这个产品进货的这个产品是什么,就有点像呢,我们这是订单啊,这个呢,是不是你订单里边具体这个呃,商品的这样的一个ID啊,诶这就相当于构成个联合索引呗。对吧,诶联合主建是吧,联合主建啊好,那这个条码呢,我们也把它呢,暂时归到咱们的这个主件里边,然后后边这块呢,这个条码啊,呃,能不能决定后边呢,这个条码呢,其实就是咱们平时买东西时候那个,呃买的那个东西的后边那个条形码呢,你想条形码都确定了,我们这个,呃,你买的是什么东西,是不是就确定下来了,那你这个东西呢,是以什么为单位的,是不是也确定下来了。
06:18
哎,这个呢,我们相当于是都能跌下来,言外之意呢,就是后边这三个字段,诶,都能够由我们这个条码呢来决定。好啊,那这块我们暂时呢,就考虑他俩,然后再往后说呢,这个诶你进货的这个数量是多少,进货的价格,还有那个进货的金额。这个后边的话呢,你看看呃,数量的话呢,完全由这个条码来决定,这好像决定不了,完全用我们这个单号来决定。诶,那你也得看你这个买的是什么东西啊,我们这儿呢是200个,这个是不是400个,诶那这时候相当于就是我们这个数量啊,应该是有我们这个单号和我们的这个,诶条码呢共同来决定的,诶那就相当于我们把这俩呢看成是一个主件,诶那这个countity,诶是不是就完全的是由这个主件来决定的是吧?诶这是数量,这个是价格,这个是金额,诶这几个呢,我们就合在一起去考虑就行,好,那么主件呢,我们确定了。
07:08
主键确定以后的话呢,接下来我们考虑这个二范式里边提到的就是你这个表里边啊假设呢,主键的是这两个字段合在一起的,后边这些呢,是不是就非主键的这些字段了,这些字段的话呢,我们要求呢,是不是得完全依赖于我们的这个,诶主见才行是吧,你要是有这个字段呢,是部分依赖了,这个呢,就不满足我马尔凡市了,我们就得需要改造,行,那这里边儿我们需要改造吗?啊,显然呢,在我们刚才分析过程当中,大家也发现了,诶,在我们前边这一块数据当中的后三个字段,是不是完全的由我们这个单号来决定了。然后呢,对于我们这样一个,嗯到哪儿啊,到这儿吧,哎这块里边呢,这是我们主键中的一部分,是不是后边这三个字段也都是由我们这个字段呢来决定。所以说呢,咱们把这两个是不是单独的得给他拿出去啊。哎,拿出去我们造成单独的一个表一个表,所以相当于我们把这个表一个表呢,是不是就拆成了三个表了,好,我们往下看。
08:02
嗯,拆成三个表,那一个呢,叫进货的单头表。啊,就是这个,诶然后呢,诶还有呢,就是我们这个商品的一个信息表啊,都拆出来了,那剩下的这些字段啊,就是我们原来的这样的一个大表是吧?诶剩下我们这两个呢,构成的一个联合组建,然后呢,后边呢,是你这个数量啊金额,呃,这个价格和这个金额啊这样的情况,这是不是就三个表了。没问题是吧,好,那这三个表出来以后的话呢,我们至少呢,目前来讲这个二范式呢是满足了。诶,二范式是满足了,呃,那么在讲这个三范式之前啊,咱们再说一个小的细节,这个细节是什么呀?就是在我们这个表里边儿呢,没有把这个情况呢给体现出来啊,但是实际情况当中呢,会出现的啊什么问题啊,就是我们大家看哈,这个条码的话呢,就是咱们一个商品中的那个条码,那比如说以这个棒棒糖为例啊,这个呢是一盒当中呢有十支,其实每一只上呢,是不是都有个条码。啊,这个是论盒卖的,有的时候呢,一些商品呢,你会在超市里边发现它可以呢,论盒卖是不是也可以散装的卖啊。
09:05
啊,散着卖一支多少钱,或者论斤卖对吧?这样的情况,那我们这里边儿的话呢,呃,这个你发现呢,散着卖跟那个按盒卖的话呢,它用的条码是一样的,我们要是用这个当主键的话呢,呃,可能会出现这个呃重复的情况,只不过在咱们这个体重没出现而已啊就好比是下边我们又出现了个0002,然后是棒棒糖,它这呢就成了这个散装的了。啊散装的了,那这个时候呢,我们用这个当主键就不太合适,所以呢,建议大家呢,我们在这个表的基础上呢,咱们专门给它提供一个列啊来充当这个主键。啊,充当一个主见,哎,那你就比如说我们这个都是0002的这样的条码,我们这个呢,比如说给的是二,哎是你这个论盒卖的啊三的话呢,就是散装卖的是吧,就区分开了。好,专门提供主件啊,这个提供完以后的话呢,我们在这个表里边儿呢,就不要用这个条码了,因为你进货的时候呢,也要指明你到底你光写0002,那到底是散装的呀,还是这个论盒卖的呀,诶这个时候我们是不是也替换成这个表里边这个主件呀。
10:02
啊,能理解是吧,好,那么这样一顿操作下来,咱们就一共呢,是不是得到了这样的几张表,哎,我把这个表呢,咱们稍微的这个截一下啊,啊,这是一张表。哎,这是一张表啊,我往这样放一下啊,然后下边这是一张表。嗯,点这个啊。啊,这张表,然后还有呢,就是咱们刚才看到的是进货单头表啊,是不是这是一张表。哎,就怕大家有点晕,所以这块我们就把它那个诶稍微的都结一下。嗯,截一下我看看啊,行,就这么着吧,就这个呢,是咱们最终考虑的这个往上提一提也行。啊,或者这样,按照我们原来这个表的顺序的话呢,是先出现在这块啊,在这块在这块行,这样呢,就满足我们目前这个第二范式的,然后接下来的话呢,我们来考虑一下这个第三范式。诶,这个第三范式呢,你得先回顾一下什么叫这个第三范式啊,还是这是一个表这儿呢,比如我们是这个表中的这个叫呃,所谓的主见吧,然后后边呢,就是非主见的这些字段了,第三范式呢,主要考虑就是你这些,诶非主见里边的这些属性,你们之间啊,是不是一定要是独立的,不能相互之间有这种依赖关系吧。
11:13
哎,这个呢,就是我们说的第三范式的要求,好,那么回过来呢,我们就一个个来分析啊,首先你看这个第一个。说第一个里边呢,我们的主见呢,就是咱们的这个第一列了,哎,那么后续的话呢,这三个之间,你看有没有相互之间依赖关系啊,一看呢,还真有啊,你看这呢,有重复数据就八成呢,这里有点问题啊。这呢是我们这个,呃,是不是进货的这个叫ID,这个呢就是name啊,那很显然这个name呢,是不是就有我们这个ID呢,就能决定了,这是不是就有依赖关系了,所以他呢是不是不满足我们这个第三范式吧。诶,他不满足我们的第三范式,好这个呢是要改造的,嗯,这个stock这这块倒没问题对吧,然后下边的话呢,我们看一看这个,嗯,这里边呢,123,然后这是条码,这是这个这些你看他们这是咱们的主见了哈,这几个之间你看有这种依赖关系吗。
12:02
我就说这俩依赖啊,这这个这这不算啊,呃,这个不一定说这个他就呃有了这个之后呢,一定这个就得是大了或啥的啊,这个这个没关系。嗯,这个呢,其实是满足我们这个三范式的啊,他没问题。啊,3万是满足,好,接着我们来看这个。这个里边的话呢,主见呢,是不是这俩,然后我们主要呢,就看后边这三个资源之间有没有依赖关系,海豚一看说啊,没事啊,走吧。有事啊,这个注意有事有什么事啊,大家你看啊,这个呢,实际上是咱们一个具体商品的一个单价啊,这个呢是你今后的数量,然后这个呢,就是乘完以后的这个结果啊,放到这儿了。啊,言外之意的话呢,就是我们这三个里边呢,是有这种依赖关系的啊,或者有这个相关性的,它倒不是说呢,这个字段完全依赖于这个字段了,但是呢,你这两个的乘积呢,是不是恰好就是后边这个值啊。哎,所以呢,他们是有这种依赖关系的,那这个时候呢,我们要改造的话呢,呃,其实呢,就相当于是我们这仨里边呢,是不是留任意两个就行啊,你比如有留前俩第三个值呢,是不是就这俩乘一得到了啊,你说我们留这俩啊,那是不是这两个除一下是不是就得到这个值了。
13:04
啊,就是这样一个场景啊,行,那就相当于是我们这个的话呢,是不是也不满足三范式啊,这也不满足,行,那下边我们就开始改造,那这个呢,既然不满足三范式,你是这俩之间存在这种依赖关系,好了,那是不是就把这俩呢单独抽出来就可以了,行,那这里边我们现在这张表呢,是不是就不要了,诶不要以后的话呢,我们把它呢,诶拆出来。啊,单独的啊,你不是Li ID跟supply name吗?哎,那你这俩呢抽出来,然后呢,我们这个进货单头表呢,就改造成这样的一个场景了。诶,就改造成这样的场景,相当于把原来那个一张表呢,是不是就变成了这两张表了,然后呢,在我们这个里边呢,你就光记住supplyd,就不要记住那个supply name了。没问题是吧,好就可以了,行,那这样的话呢,我们把这个表呢,就改造成了,那下一步的话呢,是不是要改造它呀?啊那这块我们要说明一下,诶咱们就不改造了啊这个呢,就整个呢,是咱们这个题目当中最后呢生成的这四个表。啊,这个至于说为什么不改造,咱们等着说啊,诶剩下这四个表,然后的话呢,大家再回去跟咱们最初的这样一个表呢,我们去做个对比啊,原有的这个表中,我们说呀,它就存在很多的这个冗余的信息,我们现在的话呢,就把它拆成四个,在实际呢,呃,存储的时候呢,首先啊,内存空间啊,这个存储空间是不是就节省了啊,因为你冗余数据少了嘛,其次的话呢,你在查看的时候呢,或者要查询的时候,有的时候我们也不一定非得把这个表都要用是吧,你想想你要用到这个,呃,查询这个表中啊,你要一开始用的是这个二级索引啊,然后呢,还不能够用上这个覆盖索引,是不是就要回表操作,那一旦你要回表操作的话呢,我要把这个表中呢,是不是完整的这个记录呢,都要加载进来,你看一下这个表中的字段很多。
14:41
啊,那这时候你要是查询的数据还比较多的话呢,这个加载的这个数据页呢,就会很多啊,每个页中存储的这个数据量呢,你看还很有限,因为字段多嘛。啊,那这个性能呢,肯定会比较差啊,你要拆成这几个表的以后呢啊,那你回头查询的时候,有可能我们根本也用不到,说每次都把每个表都用一下,诶性能的话呢,反而还可以啊,当然这个呢,我们是一定程度上啊得达到一个平衡。
15:04
好,那这个我们就说到这儿,然后呢,回到咱们刚才说的这个问题上说,为什么说这个里边呢,我们就不再去呃解决这个冗余问题了呢,诶这个呢,其实就我们想强调的叫反反射化啊,反反射化啊,反范式化呢,诶我们这里边提到一个叫业务优先的一个啊原则,咱们在上面呢,讲反射化的时候呢,稍微提了一下,什么叫业务优先啊,就是咱们在实际开发当中,一定是以业务需求为主的啊,咱们的技术啊是要服务于业务的,你不能反了啊,你说我们这个技术呢,应该是呃,这个为老大是吧,你业务是服务于技术的,那那那坏事。你又不是说呢去啥呀,专门呢,就是开发这些框架的公司啊,你是要做具体业务的哈,所以呢,呃,完全按照理论的设计啊,它不一定是最优的,哎,我们还需要呢,结合这个实际情况呢,咱们去做这个决定啊,那么结合实际情况,为什么说我们就不去处理这个冗余了呢?哎,这里边呢,它可能会存在一定的问题啊,你比如说。
16:02
很多时候呢,我们拿到这个呃这个这个比如说有一些促销活动的出现哈,我们拿到这个呃字段的时候呢,呃,他可能就只给我们保留这个字段了,或者这个金额是多少,一定要看到行,那按照我们这个思路的话呢,咱们就不要诶标错了啊。诶稍等啊,诶我们就不要什么呢,不要这个字段了,你要不要这个字段的话呢,我们只保留这个总的这个金额和这个康ity,诶那这时候呢,我们要想需要这个单价的话呢,是不是就要除一下啊,这个呢,有时候是搞活动的这个价格哈,搞活动以后的话,这个价格呢,你除一下我们这个数量呢,得到的这个值有时候除不尽。啊,它不像呢,说是这个乘完以后的话,得到这个值是吧?哎,它除的话有时候除不尽,那除不尽的话呢,是不是就要进行四舍五入啊,那一旦四舍五入的话呢,哎,这个呢,得到这个值跟真实这个价格呢,它就不一致了。啊,就有问题啊,你比如说啊,这个假设呢,这个是25.5,然后数量是这么多,我们这一除的话呢,是0.74啊这其实是做过这个45入啊,那你0.7次的话呢,再乘以这个34的话呢,发现结果呢是25.16,那跟这个值能看不一样了。
17:04
还挺麻烦的是吧,这不一样了啊,那暂时呢,你会发现说这个小数点后边呢,那不就差一点点嘛,但是你想想,如果我们这个,呃,整个进货的这个系统数据量在比较大的情况下呢,有一些微小的这些差别,但是在核算一起的时候呢,有可能会差几百块钱上千块钱了。啊,那这个呢,你会觉得说,哎呀,这是不是有人给这个做假账了等等的,其实呢,是由于你这里边儿这个字段的呃,省略,导致四舍五入的一个累积造成的啊,这就会有问题。对吧,那这个问题好,另外一个情况呢,你比如说我们经常性的去做一些这个查询操作。啊,经常性的做这些查询操作,然后呢,你需要呢,去查看一下我们这里边儿的这个字段。那么如果说我们要是不要这个字段呢,光要这两个字段行不行呢?呃,那就意味着你每次查询的时候呢,是不是都需要现算一下这两个的成绩是多少啊?那如果说我们要查询的这个,呃,数据量呢还比较大,而且呢,还频繁性的做这种查询,那是不是就会导致。啊导致什么呀?诶我们这个数据呢,诶数据量比较大的时候呢,诶经常性的做运算,那你花费的这个成本就会比较高,你就不如呢,是不是我们就浪费一点这个空间啊有这样的一个冗余字段,每次查的时候呢,直接拿来用是不是就行了呀。
18:15
啊,基于我们这样的两个原因啊讲解呃,那最终呢决定呢,就是我们保留了啊,这个冗余的这样一个场景。好,那么最终的话呢,咱们就是用这四个表啊,去对原有的那一个表呢,进行了一个改造啊,就是这样一个情况,好,那么大家呢,也体会体会啊,这里边我们说的这样的一个内容啊,OK,行,这个呢,就是咱们这样的一个,诶实战。
我来说两句