最近在开发新系统,理解业务,开始设计数据表结构;
寻找实体,确定实体间的关系及关系属性
梳理业务功能接口逻辑,其实也就是这个功能操作了哪张表的哪个字段
没有传说中的面向对象分析,DDD实践,流行的微服务玩法
也许,好久没有从零开发系统,很久没有亲手新建数据库表
沉默十秒钟,感觉像回到了学校,做个类似留言板,BBS类的学生系统;不是鄙视学生时代,而是有些恍惚
多年的工作经验,恍如做了个梦,现在设计的表结构与一名实习生有什么区别呢?
创建数据库表,想起了数据库范式理论,脑中一片空白呢。不得不来温习一下
范式来自英文Normal form,简称NF。要想设计—个好的关系,必须使关系满足一定的约束条件,此约束已经形成了规范,分成几个等级,一级比一级要求得严格。满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息
范式其实就是规范,这个规范还分了等级,等级越高越规范
从上面的定义可以看出规范,规范标准是要让数据库简洁,结构明晰,不要出现冗余
当关系模式R的所有属性都不能再分解为更基本的数据单位时,称R满足第一范式
第一范式讲究的是原子性,但这也跟需求相关,比如常使用的示例:
(username,address) values ("张三","江苏省南京市码农大道100号")
这儿的地址不具有原子性,需要拆分成(username,省,市,详细地址)
但如果需求不可能出现对省,市查询、分类,那其实没有必要拆分,也没有不合第一范式之说
这儿引申出一个逆向思维:两列的属性相近或相似或一样,那就得合并
(箱子编号,物品1,物品1数量,物品2,物品2数量)
这种结构满足第一范式吗?从设计上有两个弊端,物品少时会冗余;物品多时会存储不了
这只能行转列,再建新表
如果关系模式R满足第一范式,并且所有非主属性都完全依赖每一个候选关键属性,称R满足第二范式
第二范式主要是部分依赖问题
如一个电商卖家对接到个各电商平台,存储订单信息,如果所有订单都来自一个平台,可以使用“平台订单号”作为主键;如果来自多个平台,各平台的订单号可能重复,所以可以使用“平台+平台订单号”作为主键
平台 | 订单号 | 金额 | 对接人邮箱 |
---|---|---|---|
京东 | 123 | 618 | dongge@jingkong.com |
VIP | 145 | 419 | yage@vip.com |
VIP | 231 | 345 | yage@vip.com |
主键“平台+订单号”可以决定金额,但对接人邮箱只依赖于“平台”
不满足第二范式:
经常在建表时,会有一个毫无业务意义的自增字段作为主键,这样就保证了第二范式,因为主键只有一个属性,不存在真子集。同时,应当把非主属性和原来它依赖的“主键的子集”单独建表,如上表,需要加一张(平台,对接人邮箱)表
设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式
第三范式主要是传递依赖
Student(学号,姓名,年龄,所在院校,院校地址,院校电话)
学号可以确定一个学生及所在院校,但所在院校确定院校地址与院校电话
这儿需要把传递依赖项独立建表(所在院校,院校地址,院校电话)
不满足第三范式:
范式还有很多,但一般达到第三范式基本就合格了;
为什么需要范式呢?
从范式定义来讲,范式就是为了结构明晰,不出现冗余
从上面的范式递进来看,背后逻辑都体现在消除冗余,一旦出现重复数据,就想办法把这些数据抽离出独立表
在程序中,也是类似的,抽取公共部分,确定不变的,封装好变化的,保持代码简洁
那是不是必须要完全满足范式规定呢?
优点:
缺点:
优点:
缺点:
从范式优缺点看,范式也不是个银弹
比如
student(id, name),
class(id, description),
studentclass(studentid, class_id)
三张表,这样是符合数据库范式的(第一范式,第二范式,第三范式,BC范式等),没有任何冗余
如果需要列出学生的class信息,一次需要三张表的join
join性能差,那也得分三次查询
那我们可以用一张大表代替它
studentclassfull(studentid, classid, name, description)
这样name和description可能要被存储多份,但是由于不需要join了,查询的性能就可以提高很多了。
减少join除了直观地降低了高并发状态下的资源消耗外,更大的好处是降低了业务之间的耦合,增加了扩展性。
拿前面的例子来说,如果我们避免了join操作,就可以拆分成多个库,便于在一方负担过重时进行增配;或者直接改为异构、使用缓存;甚至编写独立服务成为其他业务调用的公共接口,尤其现在流行微服务架构
范式,不仅结构清晰,避免冗余,更重要的保持了一致性
如果表中存在数据冗余,同一份数据存在多个副本,是很难从逻辑上保证一致性,从应用上保证一致性,就增加了系统复杂性,所以在性能前,也不能肆意地“去规范化”
至少“去规范化”是建立在对“规划化”和应用场景的熟悉理解,对数据模型的深入思考的基础之上做出的权衡
尤其很多网页数据以表格形式显示,直接以看得见的样子建数据库的表,将会导致应用系统内部一塌糊涂,开发时举步维艰
从工程落地角度看:需求>性能>范式;但从分析角度看:需求>范式>性能
最近也是天天思考着数据模型和它们之间的关系,实体也就6个左右,各实体都有关系;系统看着也不是很复杂,花了两天才确定结构,有点能力触顶呢
抓住核心,确定主次
宽表以CQRS来实现,减少操作数据时,处理更多的表数据,增加系统复杂性,貌似CQRS就带来了复杂性
其实这篇想写更多,如NOSQL,冗余方式;篇幅太长了,再写一篇!