第3章 · 播客 第4集
数据库系统 · 反规范化四种技术
🎙️ 本集播客:第4集:规范化省了空间却拖慢了查询,于是有了反规范化。增加冗余列、增加派生列、重新组表、分割表(水平/垂直)逐一对号,学生成绩表的姓名、订单表的订单总价两个原文例子辨清冗余列与派生列的分界。 语音由微软 Edge 神经网络语音预生成(女声·晓伊,男声·云希)。点击下方任意对话可直接从该句开始播,当前句朗读时下一句已预先加载,无缝衔接。
明
阿明
上一集辛苦把表拆干净,这一集又要合回去?数据库设计师是不是在耍我?规范化不是白学了吧。
雅
小雅
不是耍你,是权衡。原文把账算得很清楚:数据库中的数据规范化的优点是减少了数据冗余,节约了存储空间,相应逻辑和物理的 I/O 次数减少,同时加快了增、删、改的速度,但是对完全规范的数据库查询,通常需要更多的连接操作,从而影响查询速度。因此,有时为了提高某些查询或应用的性能而破坏规范规则,即反规范化,也叫非规范化处理。增删改变快是规范化的功劳,查询变慢是它的代价。这条对比本身就常出判断题:说「规范化一定使所有操作都变快」,错,查询要付连接的代价。
明
阿明
反规范化有几种技术?我记得有个数字。
雅
小雅
原文列了四种:增加冗余列、增加派生列、重新组表、分割表。练习题第 9 题就考在这四种里对号。先看增加冗余列:指在多个表中具有相同的列,它常用来在查询时避免连接操作。原文例子:以规范化设计的理念,学生成绩表中不需要字段姓名,因为姓名字段可以通过学号查询到,但在反规范化设计中,会将姓名字段加入表中,这样查询一个学生的成绩时,不需要与学生表进行连接操作,便可得到对应的姓名。
明
阿明
那增加派生列呢?第 9 题的答案就是它。
雅
小雅
对。增加派生列指增加的列可以通过表中其他数据计算生成,它的作用是在查询时减少计算量,从而加快查询速度。原文例子就是第 9 题的原型:订单表中,有商品号、商品单价、采购数量,我们需要订单总价时,可以通过计算得到总价,所以规范化设计的理念是无须在订单表中设计订单总价字段。但反规范化则不这样考虑,由于订单总价在每次查询都需要计算,这样会占用系统大量资源,所以在此表中增加派生列订单总价以提高查询效率。解析里的说法是:订单总价可由商品单价乘数量计算得出,增加该列可加快查询速度;而增加冗余列是在多表中加相同列避免连接——两个定义各自的落点都回到能不能计算上。
明
阿明
提前算好存起来,查询时直接读,把计算成本挪到写入那一刻。
雅
小雅
对,这是典型的空间换时间。所以题目描述里只要出现「可以由已有的列计算得到」「避免每次查询都重新计算」这类字眼,答案就锁定增加派生列。
明
阿明
冗余列和派生列我怎么总觉得是一回事?考试这种题我全靠蒙。
雅
小雅
分界线就一条:这个字段是不是从本表其他字段算出来的。姓名算不出来,它只是从学生表抄过来的一份,所以是增加冗余列;订单总价等于商品单价乘采购数量,是可以计算生成的,所以是增加派生列。考试就爱把这两个的例子对调——把订单总价说成增加冗余列,把姓名说成增加派生列,你按「能不能算」一刀切开就不会错。
雅
小雅
来。增加冗余列:指在多个表中具有相同的列,它常用来在查询时避免连接操作。原文例子:以规范化设计的理念,学生成绩表中不需要字段姓名,因为姓名字段可以通过学号查询到,但在反规范化设计中,会将姓名字段加入表中,这样查询一个学生的成绩时,不需要与学生表进行连接操作,便可得到对应的姓名。这里的关键词是「多个表中具有相同的列」,加的是别处已有的存量信息。
明
阿明
第 9 题的干扰项还有重新组表和水平分割,这两个呢?
雅
小雅
重新组表指如果许多用户需要查看两个表连接出来的结果数据,则把这两个表重新组成一个表来减少连接而提高性能。注意它的触发条件是「许多用户需要查看连接结果」,是整表合并,不是加一列。水平分割是分割表下面的一种,等会讲。所以第 9 题判断顺序:先问是不是加了一个可计算的字段,是就选增加派生列;不是再问是不是照抄别的表的既有字段,是就选增加冗余列;整表合并是重新组表。
明
阿明
三个判断步骤,按顺序过一遍就不会乱选。分割表之前,先把分割表的总体动机说一句?
雅
小雅
原文一句带过:有时对表做分割可以提高性能。表分割有两种方式,就是水平和垂直。
明
阿明
分割表有水平和垂直两种,分别按什么切?
雅
小雅
水平分割:根据一列或多列数据的值把数据行放到两个独立的表中,切的是行。原文给了三种适用情况。情况一,表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询效率。情况二,表中的数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用。情况三,需要把数据存放到多个介质上。
明
阿明
三种情况里最容易漏记的是「多个介质」这个。降低索引层数算情况一的收益。
雅
小雅
对,情况一的完整收益链是:读的数据和索引的页数下降,加上索引层数下降,最后落到查询效率提高。选项里只写「减少数据页数」不写「降低索引层数」就是片面表述,要能识别。
雅
小雅
来。先说第一种水平分割的适用情况再补一道辨析:情况二说的「表中分别记录各个地区的数据或不同时期的数据」,和垂直分割里「某些列常用某些列不常用」,一个按行的取值、一个按属性的使用频率,考试各出各的,你盯住题目说的是「行」还是「列」就行。
雅
小雅
垂直分割:把主码和一些列放到一个表,然后把主码和另外的列放到另一个表中,切的是列。如果一个表中某些列常用,而另外一些列不常用,则可以采用垂直分割。另外垂直分割可以使得数据行变小,一个数据页就能存放更多的数据,在查询时就会减少 I/O 次数。其缺点是需要管理冗余列,查询所有数据需要连接操作。
明
阿明
水平切行、垂直切列,跟数据挖掘里的分片方式一个思路?
雅
小雅
词面一样但别混,这一集讲的是单库里的表分割,后面分布式数据库那集会讲全局关系的水平分片、垂直分片,到时候再对。这里先把两种分割的适用条件和优缺点背实:水平分割三情况是大表、数据本身独立、多介质;垂直分割的收益是数据行变小、一个数据页存更多数据、减少 I/O,代价是要管理冗余列、查全量要连接。原文还有个垂直分割的活例子:高校教职工档案,属性很多,有些需经常查询,有些则很少查询,把常用属性和非常用属性分开,就可提高对常用属性的查询速度——这个例子出成场景题,答案就是垂直分割。
明
阿明
垂直分割把主码和常用列留下,不常用的挪走,跟水平分割正好一个竖切一个横切。有没有一道题把两种混着考?
雅
小雅
有,出成场景题:说表里的数据按地区天然分开、常用的和不常用的行不一样,让你选水平分割;说教职工档案属性很多、有些属性很少查,让你选垂直分割。你就抓切的对象——按数据值分批的是水平,按属性常用与否分组的是垂直。
明
阿明
反规范化有没有副作用?总觉得加冗余不可能白加。
雅
小雅
有,而且原文在后面数据模型优化那节用另一个词又讲了一遍:把规范化的关系再合并起来,称之为逆规范化。当然,这样做会引起更新异常。总之,逆规范化有得有失,设计者可根据实际情况进行权衡。查询快了,更新就要多维护几份数据,这是永远的对价。所以题目问「反规范化的主要代价」,照着「引起更新异常、增加维护成本」这个方向选。
明
阿明
那考试里这些技术会不会要求排序或者组合?
雅
小雅
会出组合应用题:给一个查询慢的场景,让你挑技术。口诀给你——怕连接就加冗余列,怕计算就加派生列,一堆人天天看连接结果就重新组表,表太大或数据分块明显就分割。四种技术对应的痛点不同,按痛点反推技术,比死背名字稳。
雅
小雅
本集必背:反规范化是为了提高查询性能而破坏规范规则;四种技术是增加冗余列、增加派生列、重新组表、分割表;冗余列是多个表中具有相同的列用于避免连接,例子里是学生成绩表加姓名;派生列是可由其他数据计算生成的列用于减少计算量,例子里是订单表加订单总价;重新组表是把两个表组成一个表;水平分割按行的值切、适用于表大、数据独立、多介质三种情况;垂直分割把主码加常用列放一个表,收益是数据行变小减少 I/O,缺点是要管理冗余列、查全量要连接;逆规范化会引起更新异常,有得有失。
明
阿明
「能不能算出来」这一刀记住了,终于不用蒙了。下一集讲什么?
雅
小雅
数据库设计四大步骤,需求分析到物理设计,还有 1978 年新奥尔良会议、基于 3NF 的设计方法这段历史,练习题三道题都埋在那里,我们下一集见。