开发应用程序时之前最基础的工作之一是评估该使用SQL还是NoSQL 数据库来存储数据。传统数据库,即使用SQL(结构化查询语言)进行查询的关系型数据库,是经过数十年技术演进、具有良好实践和实际场景验证的。它们专为可靠事务和随机查询而设计,它们是当今大多数业务系统的基石。但它们也受到限制,例如严格的数据模型,这使得它们不太适合有些类型的应用程序。
NoSQL数据库就是为了克服这些限制而出现的。NoSQL 系统允许高性能地完成操作,给予开发人员充分灵活性来存储和管理数据。不少NoSQL数据库是由谷歌、亚马逊、雅虎和 Facebook 等公司开发的,它们需要找到更好的方法来存储大型网站的内容或处理数据。与SQL数据库不同,许多 NoSQL 数据库可以在数百或数千台服务器上水平扩展。
不过,NoSQL 的优势并非没有代价。NoSQL系统更倾向于性能和可扩展性,而不是SQL数据库所承诺的可靠事务背后的ACID属性。与数十年来围绕 SQL 建立的理论基础和实践相比,NoSQL的这些都是相对较新的。
SQL 和 NoSQL 数据库提供了不同的权衡。虽然它们可能会在特定项目的背景下竞争,但它们在更多的时候是互补的。每个都适用于不同的场景。因此,决定与其说是非此即彼的情况,不如说是哪个工具适合这项工作的问题。
NoSQL 与 SQL
SQL和 NoSQL之间的根本区别并没有那么复杂。对于如何存储和检索数据,每个人都有不同的理念。
对于 SQL 数据库,所有数据都具有固有的结构。像Microsoft SQL Server、MySQL、PostgreSQL 或 Oracle这样的传统数据库都会使用数据模型——定义数据在数据库中如何组合。例如,表中的某个列可能只能是整数,这样,列中记录的数据都必须是整数,SQL数据库的这种严格规定使得对数据执行聚合相对容易,例如使用SQL的“JOIN”命令组合来自两个表的数据。
使用 NoSQL数据库,数据可以以无模式或自由格式的方式存储。任何数据都可以存储在任何记录中。在 NoSQL 数据库中有四种常见的数据存储模型,这导致了四种常见的 NoSQL 系统:
-
文档数据库(例如MongoDB)。插入的数据以JSON 结构或“文档”的形式存储,其中数据可以是从整数到字符串再到任意格式文本的任何内容。没有必要指定 JSON 文档将包含哪些字段(如果有)。
-
键值存储(例如Redis)。值可以是任何数据类型,从简单的整数或字符串到复杂的 JSON 文档,都可以通过键(例如字符串)在数据库中访问。
-
宽列存储(例如Cassandra)。数据存储在列中,而不是传统 SQL 系统中的行中。可以根据查询或数据视图的需要对任意数量的列(以及因此许多不同类型的数据)进行分组或聚合。
-
图数据库(例如Neo4j)。数据表示为实体及其关系的网络或图形,其中图形中的每个节点都是自由格式的数据块。
NoSQL不严格数据的存储方式在以下场景中很有用:
-
希望快速访问数据,并且更关心访问的速度和简单性,而不是可靠的事务或一致性。
-
正在存储大量数据,并且不想将自己锁定在模式中,因为以后更改模式可能会很慢而且很痛苦。
-
从一个或多个来源获取非结构化数据,并且希望将数据保持在其原始形式以获得最大的灵活性。
-
希望将数据存储在层次结构中,但希望这些层次结构由数据本身描述,而不是外部模式。NoSQL 允许数据随意地以SQL数据库模拟的方式更复杂地自我引用。
NoSQL数据库的查询
关系数据库使用的SQL语言提供了一种统一的在存储和检索数据时与服务器进行通信的方式。SQL 语法是高度标准化的,因此虽然各个数据库可能以不同方式处理某些操作,但都支持SQL。
相比之下,每个 NoSQL 数据库都倾向于有自己的语法来查询和管理数据。例如,CouchDB 使用 JSON 形式的请求,通过 HTTP 发送,从其数据库中创建或者检索文档。MongoDB 通过命令行界面或语言库以二进制协议发送 JSON 对象。
一些 NoSQL 产品可以使用类似 SQL 的语法来处理数据,但仅限于有限的范围。例如,广泛的列存储 Apache Cassandra 有自己的类似 SQL 的语言,Cassandra 查询语言或 CQL。一些 CQL 语法直接来自SQL,例如“SELECT”或者“INSERT”关键字。但是在 Cassandra 中没有本地方式来执行“JOIN”或子查询,因此 CQL 中不存在相关的关键字。
无共享架构
NoSQL 系统常见的架构是“无共享(Share-nothing)”架构。在无共享架构中,集群中的每个服务器节点都独立于其他节点运行。系统无需从其他节点获得共识即可将数据返回给客户端。查询很快,因为它们可以从最近或最方便的任何节点返回。
无共享架构系统的另一个优势是弹性和横向扩展。扩展集群就像在集群中启动新节点并等待它们与其他节点同步一样简单。如果一个 NoSQL 节点出现故障,集群中的其他服务器将继续运行。即使可用于服务请求的节点较少,所有数据仍然可用。
请注意,无共享设计并不是NoSQL 数据库独有的。许多传统的 SQL 系统可以以无共享的方式设置,例如 MySQL,尽管这通常涉及牺牲整个集群的一致性以获得性能。
NoSQL的限制
你可能会问,既然NoSQL提供了如此多的自由度和灵活性,为什么不完全放弃 SQL 呢?简单的答案是,许多应用程序仍然需要 SQL 数据库提供的各种约束、一致性和保护措施。在这些情况下,NoSQL 的一些“优势”可能会变成劣势。这些约束源于这样一个事实,即 NoSQL系统缺乏某些在 SQL 领域中被认为是理所当然的特性。
没有数据模型(Schema)。即使正在接收各种格式的数据,也几乎总是需要对数据进行规范以使其方便有用。NoSQL将对数据进行规范的这个责任从数据库转移到应用程序开发人员。例如,开发人员可以通过对象关系映射系统来保证数据的结构。但是,如果您希望数据结构与数据结合一起,NoSQL 通常不支持这一点。
一些 NoSQL 解决方案为数据提供可选的数据类型和验证机制。例如,Apache Cassandra 拥有大量与传统 SQL相似的原生数据类型。
最终一致性。NoSQL系统提供了交易强一致性或即时一致性的选项,以获得更好的可用性和性能。传统数据库确保操作是原子的(事务的所有部分都成功,或者没有成功)、一致的(所有用户对数据有相同的视图)、隔离的(事务不竞争)和持久的(一旦完成,它们将继续存在)服务器故障。
这四个属性统称为 ACID,SQL都严格保证但在 NoSQL 系统中可以有不同的处理方式。您可以选择最终一致性,而不是要求整个集群的强一致性,这必然会延迟对请求的响应,它允许在不等待最新的写入被复制到集群中的其他节点的情况下处理请求。插入到集群中的数据最终随处可用,但你无法保证何时。
对于某些 NoSQL 系统,您可以选择一致性和速度之间的多种折衷方案之一,尽管可用的内容会因产品而异。例如, Microsoft 的Azure Cosmos DB允许选择每个请求的一致性级别,因此你可以选择最适合的。事务指的在一次交易或者一个活动中所有步骤(例如执行销售和减少库存)要么完成要么回滚,在一些 NoSQL 系统也已经可以提供,例如 MongoDB。
NoSQL锁。大多数 NoSQL系统在概念上相似,但实现方式不同。对于如何查询和管理数据,每种NoSQL都有自己的机制。
这样做的一个副作用是应用程序逻辑和数据库之间高度耦合。如果您选择一个 NoSQL系统并一直用它,这种耦合并没有什么问题,但如果您在未来更改系统,它可能会成为一个问题。
例如,如果从 MongoDB 迁移到 CouchDB(反之亦然),您必须做的不仅仅是迁移数据。您还必须了解数据访问和编程方法的差异。换句话说,您必须重写应用程序中访问数据库的部分。
NoSQL技能 NoSQL普及的另一个困难是缺少懂得专业知识的人才。在传统 SQL人才市场已经相对成熟,而NoSQL技能市场还是新生的。
根据人才市场的数据,截至 2022 年,传统 SQL 数据库(MySQL、Microsoft SQL Server、Oracle 数据库等)的工作机会仍然明显高于 MongoDB、Couchbase 和 Cassandra。对 NoSQL 专业知识的需求仍然只是SQL技能市场的一小部分。
SQL和NoSQL的融合
我们可以预计,SQL和NoSQL系统之间的一些差异会随着时间的推移而消失。现在已经有许多SQL数据库接受 JSON 文档作为数据类型,并且可以针对该数据执行查询。有些甚至具有对 JSON 数据进行规范,因此可以像传统的行列数据一样处理它。
另一方面,NoSQL 数据库不仅添加了类似 SQL 的查询语言,还添加了传统 SQL数据库的其他特性,例如 MongoDB 就已经提供了完整的ACID 属性。
一种可能的路径是,未来几代数据库以及当前数据库系统的未来版本将跨越范式并提供 SQL 和 NoSQL 功能,从而帮助减少数据库的用例,避免数据库世界的碎片化。例如,Microsoft 的 Azure Cosmos DB在后台使用统一的语言来处理不同数据库;Google Cloud Spanner将 SQL 和强一致性与 NoSQL 系统的水平可扩展性相结合。
尽管如此,预计未来很多年SQL和NoSQL系统仍将在各自的领地发挥作用。在更重视设计灵活性、水平可扩展性和高可用性的时候,NoSQL会被优先使用,而在重视读取一致性和其他保护措施更重要的场景中,会选择SQL数据库,此时对于应用程序来说SQL提供的保护要胜过NoSQL 提供的方便。