关系型数据库结构设计心得(一)

最近在梳理以前设计关系型数据库的心得体会,或者斗胆说是方法论,梳理出一些感觉比较干的东西,跟大家分享,以后我继续成长进步了,还会逐步更新,希望能对从事这个行业的同学有所帮助。

关系型数据库结构设计心得(一)

数据库类型的选用就不用我多说了,就是根据业务流程和数据特点,确定是用关系型还是非关系型数据库,对于非关系型数据库还要根据数据特点确定数据库存储类型,比如文档存储的mongodb,key-value存储的redis,或者图存储、列存储、对象存储、xml数据库等,都有对应的产品,不过最常用的还是mongodb和redis。

今天不谈非关系型,只看关系型数据库怎么用,怎么设计他的表结构。

一、什么时候适合用关系型数据库

关系型数据库的特点是:

  • 数据高度组织化、结构化
  • 可以使用结构化查询语言(SQL)进行多表关联查询
  • 满足ACID要求:原子性、一致性、隔离性、持久性

非关系型数据库的特点是:

  • 数据不需要高度结构化、模式化,可以灵活扩展,存储形式也比较多样(文档存储、列存储、key-value存储、图存储、对象存储、xml存储等等)
  • 没有声明性查询语言,通过内部算法调优可以满足超大数据的快速查询
  • 依据CAP定理,分为满足CA原则、CP原则、AP原则的三大类NoSQL数据库,不满足ACID要求,满足BASE要求(基本可用、柔性事务、最终一致性)
  • 也正是因为CAP定理,非关系数据库在集群支持上更灵活,也适合超大数据量的存储。

因此,我们在做一些结构比较固定、数据之间的关联性比较强的数据时,可以用关系型数据库,比如用户信息管理、商品价格管理、交易流水管理等。

那这个时候心细的同学肯定会问:这些数据用MongoDB的JSON型文档不也一样搞得定吗?

是的,所有用关系型数据库表格存储的数据,用JSON格式都可以完美存储,那MySQL这种关系型数据库和MongoDB这种JSON文档非关系型数据库之间的使用场景到底有什么区别呢?

注:这里MySQL是最常用的,阿里云上主推的关系型数据库之一,所以我们用这个来示范。

我们首先来看MySQL和MongoDB中数据都是怎样存储的:

关系型数据库结构设计心得(一)

MySQL用表存储数据,如下图中的左边示意,MongoDB用文档集合来存储数据,即写成JSON的格式,如下图的右边示意:

关系型数据库结构设计心得(一)

在查询时,由于关系型数据库的结构型查询机制,无论你用查询表中的哪一个column作为条件筛选(SQL where语句),速度都很快,还可以通过针对某些column建立索引,进一步增加速度。

而对于MongoDB来说,collection中的document是按照 _id field来建立的索引,所以在按_id检索时,速度会非常快,但是如果按其他 field 检索或筛选,在document非常大时,可能就会很慢;并且MongoDB是允许不同的document拥有不同的field的,这样检索还要判断这个document是否具有这个field,效率就不如MySQL了。

总结:

  • 如果你的数据需要结构化查询,就用关系型数据库;
  • 如果需要记录大量结构不固定的信息,而且不需要结构化查询,就用非关系型数据;

二者结合起来可以满足更多复杂系统的数据库设计。

二、基本准则

这里推荐一本书:《MySQL管理之道:性能调优、高可用与监控》

结合我自己的经验,给出2点我认为比较重要的:

1、不用外键,多用索引

不要使用外键,因为如果系统过于复杂,表的数量过多,外键关系过多,会让增删改查变得非常缓慢。因为每一步操作都要去验证外键的依赖关系,如果表中的数据记录特别多的话,是很浪费时间的。

我们一般使用代码来保障逻辑上的外键约束关系,而不是用外键。(后面的例子中会详细讲解如何使用代码保障逻辑上的外键约束关系)

我们在使用代码约束外键关系时,为了提高查询速度,还要使用索引功能,即以某个column建立索引,这样在用这个column作为筛选条件查询数据时,就会提高查询速度。

注:外键和索引的区别大家可以自行百度,本来想画个图,后来觉得我好懒,就算了。

2、表不要太大,要满足第三范式

啥叫第三范式?这事得从第一范式说起。

第一范式:数据库表中的字段都是单一属性,不可再分。

第二范式:在满足第一范式的基础上,实体的属性完全依赖于主关键字。

第三范式:在满足第二范式的基础上,不存在非关键字段对任意候选关键字段的传递函数依赖。

干不干,硬不硬,这概念多清晰。。。。貌似还是不好理解,这次我不偷懒了,上栗子:

例如我们要对如下信息建表:

病人编号,病人姓名,性别,出生日期,挂号单流水号,就诊记录,联系方式,医生编号,医生姓名,医生性别,职称,科室编号,负责人,诊室号

按照满足第三范式的要求,建表如下:

关系型数据库结构设计心得(一)

其实我在列举这些信息时,已经满足第一范式了,每一个信息都是单一属性的,不可再分。

然后按照第二范式,提取出4个主关键字(分类):病人、医生、科室、挂号就诊,其他所有信息都和这四个主关键字有关(完全依赖其中的某一个),因此我们建立4个表:病人信息表、医生信息表、科室信息表、挂号就诊信息表。

备注:在实际操作中,既可以先把所有要记录的信息列出来,再分类,也可以先分类,然后按类列举所有要记录的信息,但是在列出所有的信息后,还是要重新按照第一范式的要求去拆分去重所有的信息,然后按照第二范式去提取主关键字(分类)。

下一步,审视这四张表之间的关系(聚合、关联等),通过我们前面提到的“逻辑外键约束”的方法,将这四个表建立联系:即医生和科室之间构成聚合关系;病人和医生构成关联关系,它们通过挂号就诊信息表进行关联。

建立完成后,检查下每个表中的字段是否和其他字段构成函数依赖关系,所谓的函数依赖关系,就是 y = f(x),y字段可以由x字段推导出。

检查没问题,就完成了一个满足第三范式的建表。

备注:对于数据库建表,我们一般使用UML图来描述,一方面直观清晰。上图中我们用到了一些UML中的关系图示,下面我会详细说明最常用的2个关系及其图示,读完下面一章,再回过头看这个数据库UML图,就很清晰了。

三、两种主要的建表方法

在建表实践中,有2中方法非常重要,基本上灵活交叉使用这2种方法,就可以解决大部分复杂问题。

1、聚合关系反向建表

在上面的例子中,医生和科室有这样的聚合关系:一个科室包含多个医生,一个医生只属于一个科室:

关系型数据库结构设计心得(一)

对于这样的情况,可以用聚合关系反向建表,如下面的UML图示,这里用的是菱形实线表示聚合关系:

关系型数据库结构设计心得(一)

这里医生信息表中的“科室编号”,由代码保证它在逻辑上是以科室信息表中的主键“科室编号”作为外键的。

所谓的代码保证,即在为医生信息表写入或修改数据时,需要查询写入或修改记录的科室编号是否在科室信息表中,如果在,才能执行写入或修改操作,否则不执行并报错。

2、关联关系建表

对于上面的例子中,医生和病人有如下的关联关系:一个医生可以给多个病人看病,一个病人也可以找多个医生看病:

关系型数据库结构设计心得(一)

对于这种情况,可以用第三个表——挂号就诊表,将医生和病人关联起来,UML图示如下所示,这里用的是箭头虚线表示关联关系:

关系型数据库结构设计心得(一)

同样,用代码保证,挂号就诊信息表中的“病人编号”以病人信息表中的主键作为外键,“医生编号”以医生信息表中的主键作为外键。

四、总结

本文主要讲了一些我个人在设计关系型数据库时的心得体会和设计原则,比较简单,足以应付大多数业务。

当然,这个内容我也会持续更新,以后如果我的水平有提高了,有了新的心得体会,也会更新这篇文章,出新版本。

业界动态

从“花小猪”学:一切商业皆有可能

2020-9-12 9:51:58

业界动态

SaaS产品设计(三):SaaS 简史

2020-9-12 10:14:28

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索