10分钟入门关系型数据库(一):三范式
每天10分钟,用去食堂吃饭的时间解决一个知识点。
"10 分钟"的由来
之前在某社区看到有个同学分享了 Vue.js,10 分钟快速了解 Vue.js 的使用,我挺受启发的。也想尝试使用这种形式,帮助大家在碎片时间内,理清楚一些容易忽略的知识点。
关系
工作后由于个人很喜欢 MySQL,也接触一些 DBA 的圈子,发现挺多 DBA 会将"关系型数据库"中的"关系"一词,理解成表与表之间的关联。实际上这个词指的是关系代数。关系代数是关系型数据库的数学理论基础。我们的优化工作,本质上也是让关系运算的结果尽量地小。
从关系的角度看,我们进行数据库设计,就是将业务映射成关系的模式。而本文要复习的范式(normal form),是我们用来衡量关系的冗余程度的,目的是为了方便数据的存储和更新。本文只复习最基础的三个范式,BCNF 与第四范式,基本上实际工作中不会满足的,这里就不浪费大家时间了。
第一范式
不精确的话,只是为了直观,我们可以将关系理解成表,域理解成列。如果一个域的元素被认为是不可分的单元,那么我们将这个域称为原子的(atomic)。如果一个关系模式中每个域都是原子的,我们就说这样的设计符合第一范式(First Normal Form, 1NF)。
在实际工作中,当我们拿出一个表设计的时候,可以看成已经符合 1NF 了。为什么说"可以看成"呢?举个例子,假设我们的关系中有个属性 address,是由 province city street 组成的。如果我们是物流行业,以后会按省份或城市进行分析,在这样的场景下 address 就是可分的,那这样的设计就不符合 1NF。如果我们业务中地址只是用作一下展示,那么 address 作为一个整体就不必细分了。重点不在于域本身,而在于业务场景中要如何使用域。
函数依赖
对于元组 t1 和 t2,若 t1[α]=t2[α],则 t1[β]=t2[β],那么我们可以说这是一个函数依赖:α->β。直观的理解就是,β字段会由α字段决定。
第二范式
2NF 在 1NF 的基础上,消除了非主属性对候选键的部分函数依赖。有点拗口。一样地,不求精确的话,出于直观,我们可以理解成,非主属性要依赖于主键。在实际工作中,我们拿出一个带主键的表设计时,同 1NF 类似,实际上我们已经可以看成符合 2NF 了。因为在定主键时,我们已经考虑了业务场景中,哪些字段依赖于主键比较合适了。不会将不相干的东西揉在一张表中,基本上也就不会出现部分函数依赖。
第三范式
3NF 在 2NF 的基础上,消除了非主属性对候选键的传递函数依赖。我们可以理解成消除非主属性之间的依赖关系。那这一般出现在什么情况下呢?比如我们有一张视频表,主键为 video_id,表中记了投稿者的 ID,即 author_id,为了显示方便又记了投稿者的姓名 author_name,这就产生了传递函数依赖:video_id->author_id,author_id->author_name。3NF 就要求进行分解,即继续拆表。当然,拆不拆看你。
结语
范式只是一个工具。它的提出是为了帮助我们减少数据库的冗余性,在设计阶段为我们提供思考上的便利。前面的介绍中也可以看出,并不是一定要苛求"精确地"符合范式,我们最终的目的,还是要根据业务场景设计出合适的结构。运用之妙,存乎一心。希望本文对大家有所帮助。