面对不同数据库类型,如何进行数据库选型
数据库的选型一直是一个困扰着采购人员和DBA的问题,既需要立足于当下,提供高可用的服务,又需要着眼于未来,给予足够的扩展空间以适应项目的发展壮大。针对这个问题,本文尝试着从数据库类型的角度谈一谈数据库选型的最佳实践。
引言
如前所述,为项目进行数据库选型着实是一件头疼的事,不同的角色在选型时可能会有不同的考量。采购人员会更关注于成本及供应商资质,而DBA则会更多考虑数据库本身的性能、稳定性、扩展性等。不可否认的是,很多情况下我们可能会遇到下面这种情境。
如果你曾经使用过某类数据库,你可能会说“我只会选择 X,那是我所知道并使用过的数据库”,当然,如果性能不是重要考量标准的话,这是完全可以的。否则,当项目规模发展时,错误的数据库可能会成为项目的障碍,并且有时还很难修复。即使你正在负责一个已经使用某个特定的数据库一段时间的成熟项目,了解其局限性并清楚何时应在堆栈中添加另一种类型的数据库(多个数据组合工作是很常见的)也是很重要的。
了解不同数据库及其属性的另一个加分原因是,它是面试中的一个常考题!
在下文的内容中,我们将会讨论两种主要的数据库类型:
-
关系型数据库(基于 SQL) -
NoSQL 数据库
我们将讨论不同类型的 NoSQL 数据库以及何时使用它们。最后,我们还会讨论关系型数据库与 NoSQL 数据库的优缺点。这篇文章将不会涉及对同类型数据库的不同产品之间的比较。
关系型数据库(基于 SQL)
关系型数据库由一组连接起来的表(比如 CSV 表)组成。表中的每一行代表一条记录。
为什么叫关系型? 在这种数据库中存在的“关系”是什么?假设你有一个学生信息表和一张课程成绩表(课程,成绩,学生证),每个成绩行都与学生信息表的一条记录相关。参见下图,课程成绩表中 “Student ID” 列的值通过 “ID” 列的值指向 “Students” 表中的行。
所有关系型数据库都使用类似 SQL 的语言进行查询,这些语言很常用,并且自带 JOIN 操作(即连接操作,用于把来自两个或多个表的行结合起来,如上文的学生信息表和课程成绩表)。这种数据库支持对列进行索引,使得基于这些列能进行更快的查询。
由于其结构化的特性,关系型数据库的 schema(schema 指数据库中数据的组织和结构)是在插入数据之前确定好的。
常见的关系型数据库: MySQL、PostgreSQL、Oracle、MS SQL Server。
NoSQL 数据库
虽然在关系型数据库中,所有内容都是按行和列进行结构化好的,但在 NoSQL 数据库中,并没有针对所有记录通用的结构化的 schema。大多数 NoSQL 数据库存储的是 JSON 记录,不同的记录可以包含不同的字段。
实际上,应将 NoSQL 数据库称为“not only SQL” —— 因为许多 NoSQL 数据库支持使用 SQL 进行查询。
NoSQL 数据库按照存储结构主要分为 4 种类型:
文档存储数据库的原子单位是一个文档(document)。每个文档都是一个 JSON,不同文档可以有不同的 schema,包含不同的字段。文档存储数据库允许对文档中的某些字段建立索引,从而能够基于这些字段进行更快的查询(这将会强制所有文档都具有该字段)。
文档型数据库适用于数据分析,由于不同的记录之间并不相互依赖(在逻辑和结构方面),所以这种数据库支持并行计算。我们可以借助它来轻松地对数据进行大数据分析。
常见的文档存储数据库: MongoDB、CouchDB、DocumentDB。
2.列存储数据库
列存储数据库的原子单位是表中的一列,这意味着数据是按列存储的。它的列存储特点使得基于列的查询非常高效,并且由于每列上的数据几乎拥有相同的结构,因此可以更好地压缩数据。
列存储数据库倾向于查询数据中的一个列子集时(每次查询的数据不需要都是相同的子集!)。列存储数据库执行此类查询的速度非常快,因为它只需要读取这些特定的列(而基于行存储的数据库则必须读取整个数据)。
-
这在数据科学中很常见,其中每一列代表一个特征。作为一名数据科学家,我经常使用特征子集来训练我的模型,并且通常还会检查特征和得分之间的关系(相关性、方差、显著性)。 -
这在日志中也很常见 —— 我们通常在日志数据库中存储很多字段,但在每个查询中只使用几个字段。
常见的列存储数据库: Cassandra。
3.key-value 存储数据库
查询仅基于键 —— 当你请求一个键,便会拿到对应的值。不支持跨不同记录值之间的查询,比如 “select all records where city == New York”。这种数据库中一个有用的特性是 TTL 字段(time to live),当记录将要从数据库中删除时,这个字段可以为每个记录和状态设置不同的值。
key-value数据库的优势在于其处理速度很快。首先是因为使用唯一键,其次是因为大多数 key-value 存储数据库将数据存储在内存(RAM)中,从而可以快速访问。 它的缺点是需要定义唯一的键,这些键是很好的标识符,是在查询时根据您所已知的数据创建的。通常比其他类型的数据库更加昂贵(因为它是在内存上运行的)。
key-value数据库主要用于缓存,因为它非常快,并且不需要复杂的查询,而且 TTL 特性对缓存非常有用。它还可以用于需要快速查询并满足 key-value 格式的任何其他类型的数据。
常见的 key-value 存储数据库: Redis、Memcached。
4.图存储数据库
图存储数据库包含代表实体的节点和代表实体之间关系的边。如果数据是类似于知识图谱和社交网络这种图时适合选择图数据库。
常见的图存储数据库: Neo4j、InfiniteGraph。
关系型数据库 VS 文档存储数据库
鉴于文档型数据库,尤其是MongoDB近年来的火热,我们简要分析一下关系型数据库和文档型数据库各自的优劣势。当然,这两者之间不存在优胜劣汰的关系,没有一个数据库能够解决所有问题,选择适合自身需求的数据库才是上上之选。
关系型数据库的优点
-
数据结构简单,可以匹配项目中常见的大多数类型的数据 -
使用 SQL。SQL 很常用,并且天生支持连接操作 -
允许 数据的快速更新 。 所有数据库都保存在一台机器上,记录之间的关系用作指针,这意味着您可以一次更新一条记录,而它的所有相关记录也将立即更新 -
关系型数据库也支持原子事务。什么是原子事务:假设我想把 X 美元从 Alice 账户转移到 Bob账户。我想执行 3 个操作:减少 Alice 账户 X 刀,增加 Bob 账户 X 刀,最后记录下这个交易事务。我想把这些动作当作一个原子单位 —— 要么所有的动作发生要么一个都不发生
由于每个查询都在表上完成 —— 查询执行时间取决于表的大小。这是一个重要的限制,要求我们保持表相对较小,并在我们的数据库上进行优化以实现可伸缩性
在关系型数据库的扩展中,可以通过向运行数据库的计算机增加更多的计算能力来进行扩展,这种方法称为“纵向扩展”。为什么这是一个缺点呢?这是由于计算机能够提供的计算能力有限,而且向计算机扩展资源可能需要一些停机时间
关系型数据库 不支持 OOP,不支持面向对象,即使表示简单的列表也是非常复杂的
文档存储数据库的优点
可以保存具有不同结构的对象
可以使用 JSON 表示几乎所有的数据结构,包括基于对象的 OOP、列表以及字典
虽然 NoSQL 本质上是无模式的(指不需要像关系型数据库一样将预定义的结构,即 schema ,向数据库说明),但它通常支持模式验证,这意味着您可以使一个数据集合模式化,此模式不会像表那么简单,它是一个带有特定字段的JSON schema。(译者注:这里所说的模式就是 schema)
NoSQL 查询非常快,每条记录都是独立的,因此查询时间与数据库大小无关,并且支持并行性
在 NoSQL 中,通过添加更多的机器并在它们之间分配数据来扩展数据库,这种方法称为“水平扩展”。这允许我们在需要时自动向数据库扩展资源,并且不会导致任何停机
文档存储数据库的缺点
在文档存储数据库中更新数据是一个缓慢的过程,因为数据会在不同的机器之间进行划分、复制。
大部分文档数据库不支持原子事务。可以通过使用验证和恢复机制将其添加到代码中,但是由于记录是在机器之间划分的,所以它不可能是一个原子过程,并且可能会出现竞争状况(注:MongoDB 4.0 版本已经提供了原生的事务操作)
总结
-
对于缓存 —— 使用 key-value 数据库 -
对于类似图形的数据 —— 使用图数据库 -
如果倾向于查询列子集以及查询特征 —— 使用列存数据库 -
对于所有的其他用例 —— 使用关系型数据库或者文档存储数据库