本篇为DDIA第二章部分的内容,第二章主要介绍的是数据模型与查询语言相关的内容,这一部分作者对现在大规模数据系统所使用的到数据库类别和数据类型做了的研讨,我们所编写的系统都是围绕着数据打交道的,必然离不开数据。如何定义数据模型,然后数据通过怎么的方式去运作提供上层应用程序服务。一个复杂的应用程序大部分又很多层次,每个层次各执其职但是每层工作都是差不多提供简洁的数据模型或者操作方式,隐藏下层复杂性,有较高抽象机制能使得不同的人群可以高效协作,数据库工程师要配合着应用软件工程师一起工作,这时就需要一个规范特定的工具来协作双方工作了,例如关系数据库中的SQL语言和数据模型。


数据模型

我们日常开发一个项目都会进行需求分析阶段,这个阶段会分析一些项目中关联的东西。例如开发一个员工管理系统,需要分析一个组织的组织架构和人员关系;开发一个电商的网站需要分析商品的关系、还有用户信息、商家信息、物流信息等等,这些现实生活中的东西都能被抽象成一个数据模型来使用,在计算机里计算机可不认识这些现实的东西,需要我们程序员对其抽象包装成信息数据模型才能正常使用。然后我们就可以使用一些高级的编程语言例如Java 采用面向对象的方式进行更高级操作,而这些被操作的数据需要存储,那么就需要更通用的方式来获取数据,这时就是数据库系统了。

数据库系统可以管理这些数据,但是这些数据如何存储在数据库方便查询和操作就是一个问题了,如何把那么多的有关系的数据绑定在一起呢。这时就需要数据模型,现在最为常见的就是关系模型,这里是指一种较高的数据抽象模型,在关系型数据中这些信息被抽象成一个一个的表结构,表的关系被抽象成无序的集合,在关系数据库中的SQL叫行,而关系模型对应就是关系数据库最主要作用就是隐藏真实的数据信息,提供一个高度抽象的接口来操作,这就是日常使用最多SQL,并且还能通过安全的访问方式做数据访问操作安全控制。

但是关系模型存在一种中间层的存在例如ORM,在编写程序的时候不仅要对数据库建模,而且在对应高级OOP语言中还要对其进行数据对象映射,这就使得开发更加复杂,但是目前很多高级的编程语言都提供了ORM这类开发框架,开发者可以不用关心这样的问题,但是消除不能其底层存在的对应依赖关系,只是减少人为写一些模型之间映射代码工作而已。


NoSQL

与其关系模型对应的就是不确定数据模型或者说动态数据模型,大家都称为Not Only SQL,传统关系型数据库在单机数据数量达到上限可能就会需要优化,并且单机限制也很多也不能满足超大型的用户系统,需要使用各种分库分表或者分布式代理中间件来解决数据负载问题,不过现在还有一种新型数据叫NewSQL也能解决水平扩展问题。

而NoSQL数据库就是其数据存储可以不需要固定的表格模式以及元数据,也经常会避免使用SQL的JOIN操作,可能对关系要求没有那么严谨,可以是JSON也可以XML乃至其他的类型数据模型,可以适应日常开发者过程中数据模型动态调整问题,有时候数据不需要像关系模型那样提前建模,而是在使用的时候才能确定,这时使用NoSQL就非常适合了;并且NoSQL相比传统关系数据库更容易扩展,传统关系型数据库要满足ACID需求,而NoSQL数据相对没有这么强的要求也能更好实现水平扩展,动态扩缩容等特性,有了这些特性NoSQL适用场景就比关系型数据库多,但是一般大型的数据系统都是两种配合使用的。


关系型和文档型

书中作者提出了一个人的简历为抽象对象,如果使用的是传统关系型数据库的画,你需要的是把简历里面的内容抽象建模成一个一个表结构;而如果是非关系数据模型话,完全可以将简历的内容抽象成一个JSON对象或者结构化数据保存着;但是传统关系数据库的行也支持文本结构和JSON数据类型,另外一种方式就是把简历中的教育信息编码成JSON直接存储,或者存储在文档型数据库中,而用户信息可以存储在关系数据库中,这也是一种方案,直接存储在文档或者文本行中数据段是不能被直接通过条件查询到的。

{
  "id": 277,
  "uid": "57083634-d6a5-4236-bddf-e7d9ac54faf7",
  "city": "Joeyburgh",
  "street_name": "Yost Roads",
  "street_address": "774 Elena Turnpike",
  "secondary_address": "Suite 146",
  "building_number": "350",
  "mail_box": "PO Box 25",
  "community": "Royal Pointe",
  "zip_code": "89157",
  "zip": "40205",
  "postcode": "82387",
  "time_zone": "Europe/Sofia",
  "street_suffix": "Forge",
  "city_suffix": "port",
  "city_prefix": "South",
  "state": "New York",
  "state_abbr": "PA",
  "country": "Morocco",
  "country_code": "LI",
  "latitude": 89.48315677184291,
  "longitude": -1.4342157613853317,
  "full_address": "3044 Vandervort Ford, Francesland, WV 10942-8737"
}

例如上面这段用户信息为JSON其中一部分可以存储在文档数据库中,一部分信息也能存储在文档数据库中,JSON相当于关系模型查询的时候要联合多个表查询的结构集。JSON嵌套结构相当于一个树形结构,我们只要操作树中的一个节点就可以修改数据,这种技术在前端领域有应用JSON Patch;关系模型就不是使用结构化嵌套,而是把一个最终结构拆分成多个子表,通过相关字段或者外键互相关联数据建立关系。

文档类型的数据模型大部分都是考虑的是模型的灵活性,对应某些应用来说更关注的是数据结构的操作性,也有较好性能;而关系型更关注的是联结操作,多表联合操作,数据关系上看起来很简洁,数据就是关系是表、元组是行的集合,没有复杂的数据结构和嵌套结构,表中的记录都可以支持任意条件查询。如果你的项目中一些数据抽象结果为文档型结构能一次性加载整个树,使用文档型适合,而如果你更关注的结构拆分,把文档型的拆解成多个表,有清晰对多对关系还是用关系模型。至于用什么类型的数据库也是要在系统设计的时候考虑到的,数据之间关系,是多对一还是多对多关系,这时要考量例如一个不可变的信息可以存储在文档型数据库,而时常变化并且有多对多关系的还是存储关系数据库中方便通过条件查询,所以二者配合使用才是最佳的方案。


数据操作语言

数据模型问题已经被解决了,这时就要解决如何操作这些数据功能了,这时就需要设计一个特定操作规范去操作这些数据,例如常见的SQL语言,还有一些NoSQL特定查询语言,例如Apache Cassandra有自己设计的一套特定操作控制语言CQL。文档通常存储为编码为JSON、XML或其二进制格式,如果程序要访问之后把数据全部读取到内存修改然后再放入持久化存储中性能优势就出来了,弊端也很明显如果一次操作文档太大,也要考虑将其分割成小文档在进行操作;而关系模型多表结构这样会出现多次磁盘IO操作,需要多次检索才能得到想要的数据,这时就考虑到索引的重要性了。

在数据操作语言方面也有两种设计方式,第一种命令式语言,通俗一点来讲就是告诉计算机步骤某些操作,你可以推理整个操作逻辑然后编写对应的代码,如果是查询要考虑条件控制变量;第二种就是声明式,只指定查询结果描述满足的条件,而不需要考虑怎么去实现实际的代码逻辑,具体的操作交给数据库系统查询优化器执行操作,声明式语言有很好统一性,简洁明了的API规范,对上层用户隐藏具体的实现细节,例如Oracle里面一些特定功能,存储过程等等...


小 结

生活中的所有东西都可以被抽象一种计算机数据结构来表示,但是多个对象的曾在依赖关系,也就是关联关系,这时如果存储到一个专用的系统中就要抽象成一些特殊结构表示。这里可以使用结构化的结构,或者非结构结构,结构化抽象也可以被拆成非结构化结构,而一些非结构化也能组成结构化的,二者互补关系;这里就对应SQL和NoSQL。查询语言SQL是一种对开发人员友好的语言,它使用简单的英语,可以轻松学习管理和查询任何关系数据库,同时仅使用简单的关键字而无需编码。NoSQL没有固定查询的语言,查询不同NoSQL数据库类型的数据时使用的语法有所不同,与只有一种语言要学习的SQL不同,而不同的NoSQL的学习曲线更高,但是二者在大型数据系统中各自取长补短工作的。

其他资料

便宜 VPS vultr
最后修改:2023 年 07 月 05 日
如果觉得我的文章对你有用,请随意赞赏 🌹 谢谢 !