通过本文,我们将了解数据库如何扩展和不扩展。我们将研究传统SQL数据库存在的一些问题以及NoSQL数据库的引入如何解决这些问题。
关于基本SQL的快速回顾
SQL(Structured Query Language)数据库,也称为关系数据库,是一种基于关系模型的数据库管理系统(DBMS)。它以结构化的方式组织和存储数据,使用带有行和列的表来表示实体及其关系。
SQL数据库使用一种称为SQL的结构化查询语言与数据库进行交互。SQL提供了一组命令和语法,用于定义、操作和检索数据库中的数据。使用SQL,您可以创建表,使用主键和外键定义表之间的关系,插入和更新数据,并查询数据库以检索特定信息。
一些流行的SQL数据库系统包括:
- MySQL → 一种广泛用于Web应用程序的开源关系数据库管理系统。
- PostgreSQL → 一种以其可扩展性和高级功能而闻名的开源面向对象关系数据库。
- Microsoft SQL Server → 一种由Microsoft开发的商用RDBMS,通常用于基于windows的环境。
关于基本NoSQL的快速回顾
NoSQL数据库,也称为非关系数据库,是一种与传统SQL(Structured Query Language)数据库不同的数据库管理系统类型。
流行的NoSQL数据库包括:
- MongoDB → 一种面向文档的NoSQL数据库,提供可伸缩性、灵活性和丰富的查询功能。
- Cassandra → 一种高度可扩展和分布式的NoSQL数据库,设计用于处理跨多个通用服务器的大量数据。
- redis → 一种支持键值数据存储的内存型NoSQL数据库,提供高速数据访问。
- Amazon DynamoDB → 由Amazon Web Services(AWS)提供的全面托管的NoSQL数据库服务,提供可伸缩性、高可用性和低延迟性能。
NoSQL数据库通常用于需要处理大量快速变化的数据的情况,例如社交媒体平台、物联网应用程序等。
通过本文,我们将了解数据库如何扩展和不扩展。我们将研究传统SQL数据库存在的一些问题以及NoSQL数据库的引入如何解决这些问题。我们将涵盖适合通过SQL数据库解决的情况以及更适合NoSQL数据库的情况。
关于关系数据库的问题
关系数据库适用于各种用例,并且通常是许多开发人员在开发应用程序时的默认选择。此外,关系数据库具有SQL,这使得可以在单个数据库中处理新的访问模式以及OLTP和OLAP模式成为可能。
- OLTP → 它代表在线事务处理。它指的是支持实时事务导向工作负载的一类计算机系统和应用程序。OLTP系统旨在通过处理大量的短时且快速的数据库事务来促进和管理组织的日常运营活动。
- OLAP → 它代表在线分析处理。它指的是支持复杂数据分析、报告和决策任务的计算机系统和应用程序的一类。OLAP系统旨在处理大量数据并提供用于交互式和临时分析的多维视图。
OLTP vs OLAP[1] ← 这是一篇很好的文章,清晰地解释了OLAP和OLTP的含义及其区别,并提供了两者之间的简洁比较。如果您想进一步了解,请查看。
然而,为了提供这些功能,关系数据库通常遇到以下问题:
- 查询性能的不可预测性
- 连接的问题
- 难以水平扩展的DB实例
查询性能的不可预测性
在测试和应用程序生命周期的早期开发和发布阶段,您的应用程序通常具有快速响应的查询。
**带有5GB数据的RDBMS数据存储的表示**
然而,随着表的大小增长,这些操作会变得越来越慢。性能还受到同时运行的其他查询的影响。同时,如果公司的数据分析师在生产中对相同表进行分析操作,那么情况会变得更加复杂。
带有500GB数据的RDBMS数据存储的表示
这导致了第二个问题。
与所有著名的连接存在问题
SQL中的连接可以由于多种原因而损害速度:
- 大结果集 → 在执行连接操作时,如果连接的表之间有许多匹配行,结果集可能会显着增长。这可能导致更大的中间结果集需要处理、传输和存储,从而增加了内存消耗和较长的查询执行时间。
- 缺乏索引使用 → 有效的连接操作通常依赖于连接列上适当索引的使用。如果缺少或未正确定义必要的索引以及外键,数据库可能需要执行完整的表扫描或大量的磁盘I/O操作来定位匹配的行,从而导致性能较慢。
- 复杂的查询计划 → 数据库优化器需要确定执行连接查询的最有效方法。在某些情况下,查询优化器可能需要考虑多个可能的连接路径、表访问方法和连接算法。这个过程可能变得复杂且耗时,特别是对于具有多个连接的查询,可能导致次优查询计划和较慢的执行。
- 选择性不足 → 包括非选择性谓词(匹配大部分数据的条件)的连接条件可能阻碍性能。非选择性连接条件可能导致更大的中间结果集和较慢的查询执行,因为数据库需要处理大量数据以检索所需的结果。
为了解决这些问题,您可能希望扩展数据库,这将导致下一个问题。
DB实例的水平扩展难题
扩展数据库有两种方法:
- 垂直扩展 → 通过增加现有数据库机器的CPU或RAM
- 水平扩展 → 通过向数据库集群添加其他机器,每台机器处理总数据的一个子集。
但是,您最终会达到垂直扩展的极限。在这一点上,您可能希望考虑水平扩展。但是,这会引入一套自己的挑战。
- 数据分发和分片 → 在水平扩展时,跨多个节点分发数据至关重要。在SQL数据库中,数据通常以具有关系和依赖关系的表结构化。拆分和分发这样相互关联的数据可能会很复杂,因为维护引用完整性并确保节点之间的一致数据变得具有挑战性。通常会使用分片技术来将数据分区到节点上,但需要仔细规划,可能会引入额外的复杂性。
- 查询协调和连接 → SQL数据库支持复杂的JOIN操作,以从多个表中检索数据。当数据分布在节点之间时,执行JOIN操作变得更加具有挑战性。连接可能需要节点之间的协调、网络数据传输和增加的网络延迟,可能影响性能和可伸缩性。
- 索引和查询优化 → SQL数据库在高效的数据检索方面严重依赖于索引。随着水平扩展,索引变得更加复杂,因为需要在节点之间分布和维护索引。由于数据的分布性质,查询优化技术也变得更加具有挑战性,可能影响查询性能。
水平扩展在您可以分区单个请求可以由单个机器/节点处理的方式时效果最佳。
通过NoSQL数据库解决方案
NoSQL数据库尝试解决关系数据库提出的这些主要问题。
- 与所有著名的连接存在问题
- 查询性能的不可预测性
- DB实例的水平扩展难题
解决连接
让我们迅速了解NoSQL在这里试图解决什么。
SQL依赖于规范化来进行数据建模。
规范化是数据库设计中的一个过程,通过它来组织和结构化数据,以最小化冗余,提高数据完整
性,并优化数据库效率。它涉及将数据分解为较小、更可管理的实体(表),并在它们之间建立关系。
它旨在通过只在一个地方存储每个数据片段来消除冗余。这以以下方式使我们受益:
- 灵活的查询 → 连接允许您通过单个操作从不同表中重新组装所需的数据。有了连接的灵活性和SQL的其他语法糖,您不需要提前考虑如何访问数据。您根据规范化的原则来建模实体,然后编写查询以处理您的需求。
- 增强数据完整性 → 规范化通过定义约束和表之间的关系来帮助实施数据完整性规则。主键和外键用于建立关系和强制引用完整性,防止数据不一致并确保数据完整性。
- 提高存储效率 → 冗余数据,即相同信息存储在多个地方,可能导致不一致和浪费存储空间。只在一个地方存储每个数据片段可以降低数据不一致的机会,并提高数据准确性。
然而,所有这些都需要付出代价。CPU和内存的代价通常很高。
NoSQL采用了解决所有这些问题的方法。
- 解决灵活的查询NoSQL数据库通过要求您事先制定所有主要数据访问模式并设计数据库以处理这些问题来避免您在数据访问时灵活性的需求。您不需要在读取时汇总数据,而是通过以读取方式布置数据的方式存储数据的预连接版本。
- 解决数据完整性NoSQL数据库将数据完整性的责任推到了应用程序中。您需要将数据去规范化并复制到数据库中。在更改时,可能需要更新包含相同数据的多个记录。
- **解决存储效率**NoSQL数据库的存储效率不如其关系对手高。但是,当设计RDBMS时,存储费用相对于计算来说非常昂贵。与当前情况相比,存储价格已经大幅下降,计算则成为首选。因此,实际上通过优化计算而不是存储来对数据进行建模是非常有意义的。
SQL数据库中的数据存储示例
将此数据模型转换为NoSQL数据库,例如DynamoDB,然后它看起来像下面这样。
NoSQL数据库(DynamoDB)的对应数据存储示例
解决水平扩展
关系数据库之所以很难水平扩展的主要原因是查询语法的灵活性。由于数据访问模式的灵活性,系统不知道哪些数据将在查询实际执行之前被获取。因此,为了避免在执行查询时进行跨机器网络调用,所有数据都必须保持在本地,即在同一节点上。
NoSQL数据库通过要求将数据拆分为较小的段并在这些段之一中执行所有查询来采用水平扩展。
为了更好地了解这一点,让我们以user_id作为分区键,并在图中进行跟踪。
大多数NoSQL数据库在将分区键值分配给节点之前对其进行哈希处理。这有助于更好地分发数据。
在读取和写入操作期间,所有查询必须包括分区键,以便直接访问相关节点。
解决查询性能的不可预测性
在SQL数据库中,随着表的大小增长,操作会变得越来越慢。性能还受到同时运行的其他查询的影响。
对于NoSQL数据库的读取操作,所有查询必须包括分区键。在执行写入操作时,可以将此操作发送到负责该数据块的节点,而不会打扰群集中的其他节点。随着数据量的增加,可以根据需要继续添加额外的节点。每个操作仅影响群集中的一个节点。与SQL数据库中的测试和生产环境相比,查询性能几乎不会有太大差异,因为每个操作仅影响一个节点。