聊一聊数据模型与查询语言

212 阅读15分钟

数据模型是用于组织、描述和定义数据及其关系。数据模型可以帮助我们理解数据的结构和含义,为建立、设计和管理数据库提供指导。数据模型不仅影响着软件的编写方式,而且影响着我们的解题思路。不同的数据模型其实也对应了不同的数据库。

关系模型

关系模型由英国计算机科学家埃德加·科德在1970年首次提出。它基于数学上的集合理论和逻辑理论,使用二维表格结构来表示数据和数据之间的关系,这些表格被称为“关系”。

在关系模型中,每个关系代表一个多维数据集,表格中的每一行(也称为元组或记录)代表一个实体实例,每一列(也称为属性或字段)代表一个实体的一个属性。

以下是关系模型的一些关键概念:

  1. 关系(Relation) :关系是一组具有相同属性的元组的集合。在数据库中,关系通常被表示为一个表,其中表的每一行代表一个元组,每一列代表一个属性。
  2. 属性(Attribute) :属性是关系的一部分,代表关系中元素的某个特性。在表中,属性通常被表示为列。
  3. 元组(Tuple) :元组是关系的一个实例。在表中,元组通常被表示为行。
  4. 键(Key) :键是一个或多个属性的集合,可以唯一标识关系中的元组。主键是关系中的一个特殊键,它唯一标识关系中的每一个元组。

关系模型的一个主要优点是其简单性和形式化。通过使用标准的SQL(结构化查询语言),用户可以方便地查询和操作关系数据库。

数据库范式

在关系模型中,需要将现实中的问题抽象到关系模型中,转化为对应的表。在设计时,通常使用不同的数据库范式进行指导,一般需要满足第三范式。当然,有时出于性能或使用复杂度考虑,也会采用一些反范式的设计,这里不做讨论。使用数据库范式的本质是提高数据的一致性,减少数据冗余,并简化数据管理。

数据库范式主要包括第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、BCNF(Boyce-Codd范式)、第四范式(4NF)和第五范式(5NF)。这里,我将通过一个简单的例子来介绍前三种最常用的范式。

设计一个系统,支持查询学生查看自己的课程与课程老师,其关系如下:

student_idstudent_nameclassteach
1小明数学李老师
1小明英语王老师
2小红数学李老师
2小红英语王老师

第一范式 1NF :每一列都是不可分割的最小单元,每一行都是唯一的。在我们的例子中,表已经满足第一范式,因为每一列的值都是不可分割的。

第二范式 2NF :在第一范式的基础上,每一行都要被唯一的区分,且非主键列必须完全依赖于主键。在我们的例子中,主键为「student_id, class」。student_name 只依赖 student_id,tech 只依赖 class。因此,需要进行拆分,在拆分 class 时,通常为新的表增加一个 id 列作为主键。

image.png

第三范式 3NF :在第二范式的基础上,每一列都与主键有直接依赖关系,不存在非主属性对非主属性的依赖。在我们的例子中,已经满足第三范式。

查询语言-SQL

SQL,全称为Structured Query Language(结构化查询语言),是用于处理关系型数据库的标准计算机语言。SQL允许用户访问和操作数据库,它包括数据查询、数据操纵(插入、更新和删除)、数据定义以及数据控制等功能。

以下是关于SQL的一些详细介绍:

  1. 数据查询(SELECT):这可能是SQL中最常用的命令,用于从一个或多个表中获取数据。
  2. 数据操纵语言(DML):包括INSERT(插入)、UPDATE(更新)和DELETE(删除)命令,用于在表中插入新数据、更改已有数据或删除数据。
  3. 数据定义语言(DDL):包括CREATE(创建)、ALTER(修改)和DROP(删除)命令,用于创建、更改或删除数据库对象,如表、索引和序列等。
  4. 数据控制语言(DCL):包括GRANT(授权)和REVOKE(取消授权)命令,用于控制对数据库对象的访问权限。
  5. 事务控制语言(TCL):用于管理数据库中的事务,包括BEGIN TRANSACTION(开始事务)、COMMIT(提交事务)和ROLLBACK(回滚事务)等命令。

SQL是一种声明性语言,用户只需要指定他们希望执行什么操作,而无需指定如何执行这些操作。这使得SQL相对容易学习和使用。大多数现代的关系型数据库系统,如 MySQL、Oracle、SQL Server、SQLite 和 PostgreSQL 等,都支持SQL。

示例

下面是一个领应页面的展示数据,按照第三范式,需要设计 users、industries、position、education、contact_info 表。

文档模型

在上面的例子中,使用第三范式设计表存储领英主页数据。在一次页面展示时需要关联查询 6 张表,才能展示主页所需要的数据。那能否使用一种模式,仅需要一次查询即可以获取全部数据,减少查询的开销。

对于像简历这种包含文档的数据结构而言,使用 JSON 表达非常合适。可以使用面向文档的数据库「MonogoDB、CouchDB 等」来存储数据。针对上面的例子可以使用一个 JSON 表示。

{
  "user_id": 251,
  "first_name": "Bill",
  "last_name": "Gates",
  "summary": "Co-chair of the Bill & Melinda Gates... Active blogger.",
  "region_id": "us:91",
  "industry_id": 131,
  "photo_url": "/p/7/000/253/05b/308dd6e.jpg",
  "positions": [
    {
      "job_title": "Co-chair",
      "organization": "Bill & Melinda Gates Foundation"
    },
    {
      "job_title": "Co-founder, Chairman",
      "organization": "Microsoft"
    }
  ],
  "education": [
    {
      "school_name": "Harvard University",
      "start": 1973,
      "end": 1975
    },
    {
      "school_name": "Lakeside School, Seattle",
      "start": null,
      "end": null
    }
  ],
  "contact_info": {
    "blog": "http://thegatesnotes.com",
    "twitter": "http://twitter.com/BillGates"
  }
}

使用文档模型减少了应用程序代码和存储层之间的阻抗不匹配「即实际存储的模型与应用层展示的模型不一致」。使用文档数据库的优势在于使用 JSON 将所有相关信息都放在一个地方,一次查询就可以完成。且无需像关系数据库一样有严格的关系约束。

对于多对多的关系,无论是关系模型还是文档模型,最终都将进行关联查询。区别在于一个是关联不同的表,一个是关联不同的文档。以上面的个人主页为例,需要在展示的公司和学校详情上增加对应的官网链接。一种方式是在每个 uses 文档中添加对应的数据,造成大量数据的重复且不利于维护。因此,需要将需要内的数据分组为一个文档,同时保存对单位、学校的引用,在查询时需要进行连接。

查询语言

文档数据库的查询语言各有不同,根据所使用的数据库类型而异。以下是一些常见的文档数据库及其查询语言:

  • MongoDB: MongoDB 使用 MongoDB 查询语言(MQL)。这是一种功能强大且灵活的查询语言,允许用户查询文档的任何部分,支持各种类型的查询运算符(如比较、逻辑、数组等),并包含对索引、聚合和全文搜索的支持。
  • CouchDB: CouchDB使用CouchDB Query Language,它是基于JSON 的,允许创建各种复杂的查询,包括地理空间查询。
  • Elasticsearch: Elasticsearch使用 Elasticsearch Query DSL,这是一种基于JSON 的查询语言,特别适合全文搜索和复杂的数据分析。
  • Firestore: Firestore使用Firestore查询语言,它允许创建简单但强大的查询,可以查询、排序和过滤文档。

这些查询语言的共同之处是,都允许使用JSON格式来表示查询条件,可以非常灵活地查询文档的各个部分。然而,它们在语法、功能和性能方面都有所不同,用户需要根据具体的需求和环境来选择合适的数据库和查询语言。

图模型

图模型的提出是为了解决更复杂的多对多关系,使用图模型可以将复杂关系的写入和查询进行简化。依赖图模型可以简单进度深度和广度遍历对应的节点。典型的例子包括:

  • 社交图谱:顶点是人,边指示哪些人彼此认识。
  • 网络图谱:顶点是网页,边缘表示指向其他页面的 HTML 链接。
  • 公路或铁路网络:顶点是交叉路口,边线代表它们之间的道路或铁路线。

基本概念

  1. 节点(Node):节点通常用于表示实体,比如人、地点、物品等。
  2. 边(Edge):边用于表示节点之间的关系。边可以是有向的(表示关系的方向)或无向的,也可以带有权重(表示关系的强度或其他属性)。
  3. 属性(Property):节点和边都可以有属性,这些属性是键值对,用于存储与节点或边相关的信息。
  4. 图(Graph):图是由节点和边组成的结构。在一个图数据库中,可以有一个或多个图。
  5. 子图(Subgraph):子图是图的一部分,包含一些节点和连接这些节点的边。
  6. 邻居(Neighbor):一个节点的邻居是与该节点直接相连的其他节点。
  7. 度(Degree):一个节点的度是与其相连的边的数量。
  8. 路径(Path):路径是通过边连接的一系列节点。

查询语言

图模型的查询语言有很多种,依据所使用的图数据库类型而异。以下是一些常见的图数据库及其查询语言:

  1. Cypher:这是Neo4j图数据库的查询语言。Cypher是一种声明式的图查询语言,它允许开发人员使用类似于SQL的语法来查询图数据。
  2. Gremlin:这是Apache TinkerPop图计算框架的查询语言。Gremlin是一种函数式的图遍历语言,可以用于查询、分析和操作图数据。
  3. SPARQL:这是用于RDF(资源描述框架)数据模型的查询语言。SPARQL可以用于查询、更新和操作RDF图数据。
  4. GraphQL:虽然不是专为图数据库设计,但GraphQL是一种用于API的查询语言,能够直观地描述数据的形状和方式,让客户端能够精确地获取需要的数据。

这些查询语言都能有效地查询和操作图数据,但在语法、性能和功能上都有所不同。用户需要根据具体的需求和环境来选择合适的查询语言。

示例

如下图所示,它显示了两个人,来自爱达荷州的 Lucy 和来自法国 Beaune 的 Alain。他们已婚,住在伦敦。

KV 模型

KV模型,也就是键值对(Key-Value)模型。在这种模型中,数据被表示为一系列的键值对。

  • 键(Key):键是唯一的标识符,用于定位到存储的数据。键可以是任何类型的数据,比如字符串、数字,甚至可以是复杂的数据类型。为了快速查找数据,键通常会被索引。
  • 值(Value):值是与键关联的数据。值可以是简单的数据类型,如数字、字符串,也可以是复杂的数据类型,如列表、字典或对象。

KV模型的优势在于简单和高效。由于数据的存储和检索都是基于键的,这使得 KV 模型在处理大量数据时能提供高性能的读写操作。这种模型特别适用于需要快速访问并且数据模型简单的应用,例如缓存系统、会话管理等。

然而,KV模型也有一些限制。它不支持复杂的查询,如多键查询或基于值的查询,也不支持数据之间的关系。此外,由于数据模型的简单性,可能需要在应用程序中处理更多的数据结构和关系复杂性。

查询语言

键值存储(Key-Value Store)的查询通常比较简单,主要是基于键(Key)的获取(Get)、设置(Set)和删除(Delete)操作。由于它们的数据模型相对简单,键值存储通常没有复杂的查询语言,例如SQL。下面是一些基本的操作示例:

  • Get(Key): 根据提供的键获取对应的值。
  • Set(Key, Value): 将特定的值存储在给定的键下。
  • Delete(Key): 删除存储在给定键下的值。

例如,如果你正在使用Redis(一种流行的键值存储),你可能会使用以下命令:

  • GET mykey: 获取名为"mykey"的键的值。
  • SET mykey myvalue: 设置名为"mykey"的键的值为"myvalue"。
  • DEL mykey: 删除名为"mykey"的键及其值。

需要注意的是,这些操作都是基于键的。键值存储通常不支持基于值的查询或复杂的多键查询。这也是为什么键值存储特别适合于读写密集、数据模型简单的应用场景。

向量模型

向量模型,或称为向量空间模型,是一种常用于信息检索和自然语言处理中的数学建模方法。在该模型中,文本(如文档或查询)被表示为在多维空间中的向量。每个维度对应于一个特定的词或概念。向量模型主要用于解决相关性检索的问题,多应用于 AI 模型中的数据预处理。

向量模型的主要思想是通过空间中的向量来度量文本之间的相似性。通常,两个向量之间的角度(或余弦相似性)被用来度量文本之间的相似性——角度越小(或余弦相似性越高),相似性越大。

以下是向量模型的一些核心概念:

  1. 词项(Term):即词语,作为向量空间的维度。
  2. 文档向量(Document Vector):每个文档在向量空间中都有一个向量表示。向量的每一维都对应一个词项,其值通常是该词在文档中出现的频率(可能经过TF-IDF等权重计算)。
  3. 查询向量(Query Vector):用户查询也可以被转化为向量,方法和文档向量相同。
  4. 相似性度量(Similarity Measure):度量文档向量和查询向量之间的相似性。常用的度量方法是计算两向量的余弦相似性。

使用向量模型进行信息检索的一般过程是:首先,将所有文档和用户的查询转化为向量;然后,计算查询向量和每个文档向量的相似性;最后,根据相似性的高低对文档进行排序,返回最相关的文档。

向量模型的一个主要优点是它能够处理语义上的模糊性,因为它允许对相似(而不是完全匹配)的概念进行匹配。其缺点包括处理布尔查询的能力较差,以及需要大量的存储空间和计算资源。

总结

数据模型是对数据组织、定义与关系的一种描述。对于现实中的业务场景,使用关系、文档、图、KV 等模型均可以组织数据。但是,在数据模型选型时,本质是要看对应的模型能否方便业务代码开发,简化写入和查询逻辑,并保证高性能。

并没有一种数据模型能够解决所有的问题,每一种数据模型都有自己的优缺点。针对于数据模式不固定且关系简单的场景,优先考虑文档模型;对于数据模式固定,且需要严格保证数据约束,可以考虑使用关系模型;对关系复杂的场景可以使用图数据库;对于 KV 模型则更多的应用于缓存中。当然,在数据模型选型时,除了需要对应的数据模型,还需要考虑相关模型数据库的可伸缩性、可靠性、对事务和复杂查询的支持等各种因素。

随着不同数据库的迭代,各种数据库之间的差异也在不断减少。目前的关系模型数据库「MySql, PG」均已经支持 JSON 数据的存储,这就意味着你可以使用关系模型数据库定义文档;而对于文档数据库如 Monogo,也已经支持不同文档之间的关联,以及严格的约束文档的定义。