在熔炉 - NoSQL?我更喜欢 SomeSQL

作者:Reuven M. Lerner

当我在 1990 年代初期开始开发 Web 应用程序时,我有时发现自己需要存储持久性数据。当时,可用的主要选项是文件——纯文本文件、二进制文件或 DBM(现在是 Berkeley DB)文件。

幸运的是,我当时用于 Web 开发的语言(主要是 Perl 和 Tcl)使得使用任何这些选项都相当容易。然而,像我这样的 Web 开发人员很快发现了这些技术固有的问题,尤其是在大型站点上。缺乏智能的、细粒度的锁定意味着流行的应用程序将被迫等待才能从外部文件读取或写入。此外,以这种方式存储数据阻止了我们智能地或有选择地检索数据。当然,您可以将数据读入您的程序并生成您自己的报告,但每个报告不仅需要自己的查询,还需要自己的程序。

因此,您可以想象当我被介绍到关系数据库系统时,我的生活发生了多么巨大的变化。简而言之,关系数据库是由许多二维表构建的,每个表包含一个或多个列(属性)和一个或多个行(记录)。您可以使用外键将这些表相互关联(因此,使数据库“关系化”),以便一个表中的列代表另一个表中的记录。

当您将数据存储在关系数据库中时,您突然能够停止考虑数据如何存储,而更多地考虑其结构。数据库服务器是以二进制格式、ASCII 格式还是完全不同的格式保存信息?谁知道?更重要的是,谁在乎?只要我可以轻松高效地存储和检索我的数据,我就会将数据库视为一个黑匣子,专注于编写我的应用程序。

SQL,即与关系数据库一起使用的查询语言,鼓励这种思维方式。当您使用 SQL 查询数据库时,您描述的是您想要检索的数据,而不是告诉计算机如何检索它。诚然,现在 SQL 有过程扩展,您也可以使用非 SQL 语言编写程序,以进一步处理数据。但是,即使它们也允许您循环、操作和对检索到的数据执行计算。数据本身仍然在数据库中,您仍然以 SQL 的声明性语言描述您想要检索的方式和内容。

关系数据库变得流行,因为它们为程序员提供了如此多的优势。它们提供了稳定性和安全性。它们提供了事务,允许程序员确保一组操作要么全部原子地发生,要么回滚到查询开始执行之前的状态。将多种类型的数据映射到二维表上相当容易。数据库获得了各种各样的功能,包括检查它们存储的数据完整性的能力。而且,它们甚至获得了在多台计算机上分配负载的能力,尽管这有一定的难度。

开源关系数据库,如 MySQL 和 PostgreSQL,开始挑战其商业竞争对手。当我在 1996 年开始撰写这个专栏时,MySQL 尚未在开源许可下发布,虽然 PostgreSQL 完全是开源的,但它有一些限制。因此,人们期望如果您有兴趣使用关系数据库,您几乎肯定会为它掏钱,向 Oracle 或其较小的竞争对手之一支付数千美元。今天,情况恰恰相反。开源数据库对于 Web 应用程序来说绰绰有余。此外,基本上可以预期 Web 应用程序将使用关系数据库作为后端。如果您说您是一名 Web 开发人员,基本上可以预期您有一些 SQL 经验,以及对关系数据库的关怀和感觉。

那么有什么问题呢?

我已经使用关系数据库多年了,我对它们非常满意。事实上,正如我有时告诉我的客户的那样,我通过二维表看世界。将问题分解为表格以及它们之间的关系是我几乎每天都在做的事情。然而,即使我认识到数据库是一种工具,并且并非每种工具都适用于每项任务。说每个 Web 应用程序都应该使用关系数据库就像说所有程序都应该用 C 语言(或您目前最喜欢的任何编程语言)编写一样。正如古老的谚语所说,如果你的唯一工具是锤子,那么每个问题看起来都像钉子。

而且,在过去几年中,关系数据库确实出现了一些问题。也许许多开发人员面临的最大问题是对象(我们喜欢用它编写程序)和表格(关系数据库在其中运行)之间的“阻抗失配”。如果您想将您的对象存储在数据库中,您有几个选项,但没有一个特别好,而且所有选项都会丢失一些语义价值,而语义价值正是对象的全部意义所在。诚然,您可以将每个对象属性视为一列,将每个实例视为一行,将每个类视为一个表,但是许多边缘情况不能很好地映射到这一点,即使使用优秀的 ORM(对象关系映射器)库也是如此。我喜欢使用 Ruby on Rails 的原因之一是 ActiveRecord 能够在很大程度上掩盖这些差异,但即使 ActiveRecord 拥有所有的智能,有些问题也无法通过对象轻松解决,在这些问题中,需要按摩我的数据模型,甚至要深入到 SQL 中。

在过去几年中,随着包含许多不同类型数据(其中一些是不可预测的或包含高度可变的内容)的文档和对象的增长,这个问题变得更加严重。为了响应这些需求,数据库服务器已经开始合并以前被认为在数据库领域之外的功能,例如全文搜索(非常有用)和 XML 处理(我仍然觉得令人困惑并且有点不合适)。无论您对这些功能持何种态度,仅仅为了存储和检索文件而设置数据库服务器似乎有点奇怪。必须有更好的方法来存储这些文件,而无需与数据库服务器相关联的所有管理和计算开销。

另一个问题与 Web 应用程序越来越高的性能要求有关。我倾向于不理会关于“可扩展”语言和框架的讨论,部分原因是我相信任何语言或框架都可以扩展,只要有足够的硬件。与其担心特定语言的可扩展性,我更愿意关注架构的可扩展性——这当然是关系数据库服务器的弱点。使用“无共享”方法的现代 Web 应用程序可以轻松扩展到数百甚至数千台 Web 服务器,每台服务器处理部分负载。但是,如果每台服务器都需要与后端的数据库服务器通信,那么数据库在某个时候可能会不堪重负。即使在开源数据库中,也有解决这个问题的方法,但它们的安装和配置远非简单。

NoSQL?我更喜欢 SomeSQL

日益可变的文档类型以及与 Web 应用程序相关的可伸缩性问题,导致 Web 开发人员社区中的许多人推动 NoSQL,这是一种仅在拒绝关系数据库模型方面团结一致的各种解决方案。这个术语本身是在 2009 年由 Eric Evans 创造的,他想描述当时正在兴起的非关系工具的集合。当我在 2010 年初撰写本文时,我们正在看到一场真正的 NoSQL 革命,许多著名的 Web 开发人员和站点正在从关系数据库服务器转向其他系统。

切换到这些各种 NoSQL 系统的原因因站点和开发人员而异,但它们与我上面概述的原因相呼应:与用于编程应用程序的对象良好匹配,面向文档的数据库提供的灵活性以及 NoSQL 系统提供的更容易的复制。这些系统在方法、通信或性能方面远非相同,但它们都有自己的支持者,并且在开源许可证下发布。此外,这些系统中的许多系统目前正在 Facebook 和 LinkedIn 等高性能 Web 站点上使用,因此如果您的站点比这些站点小,那么这些解决方案很可能也适用于您。另一个优点是,这些系统中最流行的系统提供了许多语言绑定,因此无论您使用 Ruby、Python、Java 还是 PHP 都无关紧要。

在讨论 NoSQL 解决方案时,我最常听到的名字是 CouchDB 和 MongoDB,其他(如 Tokyo Tyrant)也获得了大量提及。CouchDB 的突出地位很大程度上归功于其在 Erlang 中的实现以及其使用 JSON 作为查询和响应格式,以及其数据库功能。CouchDB 允许您在数据库上使用著名的 map-reduce 算法,用 JavaScript 编写函数,并通过 HTTP 使用 REST 发送查询。相比之下,MongoDB 是用 C++ 编写的,并使用其自己的面向对象的系统 (BSON) 来处理查询。我仍在考虑两者之间的差异,并试图理解它们各自可能具有优势的地方。

我毫不怀疑这些 NoSQL 解决方案可能非常有用,并且确实解决了许多问题。但是,我很大程度上怀疑我们是否真的应该抛弃 30 年来关于关系数据库的累积知识。此外,关系数据库的设计目的是确保数据完整性,而不仅仅是数据的快速存储和检索。而且,尽管这些现代 NoSQL 解决方案可能确实快速且灵活,但它们缺乏完整性检查确实让我有些担忧。也许我过时了,但我喜欢我可以将关系数据库表定义为 NOT NULL 或 UNIQUE 的事实,从而知道其中包含的数据存在、唯一或两者兼有。我喜欢知道我的数据库中的每个记录都有一个唯一的标识符。我喜欢能够遍历外键,这样当一个记录指向另一个记录时,我知道另一端会有东西,而不是数据库等效的空指针。我也很好奇地想知道这些数据库如何避免数据重复,或者 NoSQL 中与“规范化”等效的概念是什么。

因此,我认为那些认为 NoSQL 是所有应用程序存储需求的完整解决方案的人夸大其词了,并且忽略了与关系数据库相关的许多智慧。数据库运行得非常好,并且现在非常容易使用,因此仅仅因为它们在处理顶级 Web 应用程序的负载时遇到困难就将它们放到牧场似乎是一种耻辱。

事实上,对于 NoSQL 产品似乎没有解决方案的各种问题,至少目前是这样。他们不关注数据完整性,无论是缺少空数据还是确保只允许存储某些值。它们不提供任何在多个维度上将对象相互关联的方式,我发现这是关系模型最具吸引力的元素之一。而且查询语言远未标准化,这意味着从一个 NoSQL 解决方案迁移到另一个解决方案需要将查询从一种语言翻译成另一种语言。

也就是说,越来越多的 Web 应用程序类别,关系数据库不太适合,而面向文档的方法可能确实更优越。我的论文软件处理大量文本文档,很可能是一个很好的例子,说明一个程序可以从面向文档的方法中受益,我已经开始探索这种替代方案。然而,即使我将部分软件切换为使用 NoSQL 解决方案,它也只是用于部分数据存储,而不是全部。通过这种方式,我希望从两全其美中受益,在有意义的地方使用关系数据库,在提供更优越解决方案的地方使用文档数据库。

我的感觉是,NoSQL 运动,至少在其名称所投射的形象中,有点极端,并且未能认识到许多关系解决方案的优势和复杂性。我更喜欢一种更细致的方法,可以称之为 SomeSQL,其中非关系数据库被视为额外的工具,可以(希望)集成到更大的数据存储解决方案中。毕竟,memcached 和关系数据库已经设法和谐共处多年了。凭借一点规划,并使用正确的工具,我认为 SQL 和 NoSQL 的组合可能会非常强大。

当然,NoSQL 人员完全正确的可能性也存在,我们正在看到一种技术衰落,另一种技术兴起。也许我们正处于新革命的前沿,这是 1990 年代高级“脚本”语言增长的数据库等价物。但是,我更愿意将此视为 Web 开发人员必须融入其工具箱的新技术,并且他们需要在设计和编写新的 Web 应用程序时理解它。

在接下来的几个月中,我计划探索一些更知名的 NoSQL 解决方案。我将从开发人员的角度来看待它们——它们提供什么,以及为什么我要选择它而不是关系数据库或其 NoSQL 竞争对手?我还不能说哪种技术会成为我的最爱,或者哪种技术适合您的应用程序。但是,我确实相信 SomeSQL 方法有可能显着提高我们应用程序的灵活性和性能,但代价是我们过去几十年已经习惯的数据存储简单性。

资源

很难总结迄今为止关于 NoSQL 的所有著作。来自 2009 年年中 NoSQL 会议的许多视频和演示都链接到 Johan Oskarsson 在 blog.oskarsson.nu/2009/06/nosql-debrief.html 上的博客文章中。

有关 CouchDB 的更多信息,请访问 couchdb.apache.org,有关 MongoDB 的更多信息,请访问 mongodb.org

对于一些有趣的回应(和拒绝)NoSQL 运动的评论,您可能想阅读以下一篇或多篇文章:www.eflorenzano.com/blog/post/my-thoughts-nosqlcacm.acm.org/blogs/blog-cacm/50678-the-nosql-discussion-has-nothing-to-do-with-sql/fulltextcodemonkeyism.com/dark-side-nosqlbjclark.me/2009/08/04/nosql-if-only-it-was-that-easy

Reuven M. Lerner 是一位长期的 Web/数据库开发人员和顾问,是西北大学学习科学博士候选人,研究在线学习社区。在芝加哥地区生活了四年后,他最近(与妻子和三个孩子)返回他们在以色列莫迪因的家。

加载 Disqus 评论