图片来源Adobe Stock
翻译《Designing Data-Intensive Applications》
作者Martin Kleppmann
译者雨钓
类别 图书 / 计算机
Kristen Brown / 2017-03-01: First Release
SQL与NOSQL起源于优劣对比
01
SQL
今天最著名的数据结构可能就是SQL了,一种 基于Edgar Codd在1970年提出的关系模型[1]: 数据被组织成关系(SQL中的表),其中每个关系是一个无序的元组集合(SQL中的行), 关系模型是一个理论上的建议,许多人当时怀疑它是否能有效地实现。 然而,到20世纪80年代中期,关系数据库管理系统(RDBMSes)和SQL已经成为大多数人的首选工具,他们需要存储和查询带有某种regular结构的数据。 关系数据库的主导地位持续了大约25-30年——这在计算历史上是绝无仅有的;
关系数据库的根源在于业务数据处理,执行在上世纪六、七十年代的一种大型计算机上。针对的用例从今天的角度来看是很平常的:典型的交易处理(进入销售或银行中转业务,航空公司预订,仓库库存)和批处理( 用户的发票、工资、报告), 当时的其他数据库迫使应用程序开发人员对数据库中数据的内部表示进行了大量的思考。 关系模型的目标是将实现细节隐藏在一个更干净的接口后面。
多年来,数据存储和查询的方法有很多。 20世纪70年代和80年代初,网络模型和层次模型 是主要的选择。 但关系模式开始主导(dominate)他们。 在上世纪80年代末和90年代初,object数据库再次出现, XML数据库出现于本世纪初,但只出现了小众的采用。 对关系模型的每个竞争对手(competitor)在其时间内都产生了大量的炒作(hype),但它从未持续下去(never lasted)[2]
随着计算机变得更加强大和网络化,它们开始被用于越来越多样化的用途。值得注意的是,关系数据库在其原始的业务数据处理范围之外,非常好地推广到WEB的用例。 你在web上看到的许多东西仍然是由关系数据库驱动的,比如在线发布、讨论、社交网络、电子商务ecommerce、游戏、软件即服务的生产力应用程序,或者更多。
02
The Birth of No SQL
现在(2010年) NOSQL是推翻关系模型统治地位的最新尝试。“No SQL”这个名字是不幸的,因为它实际上并不是指任何特定的技术——它最初只是作为一个简单的Twitter 标签 for 在2009年在开放源码,分布式,非关系数据库中作为一个meetup。[3] 从来没有过,这个词触动了神经,很快就传遍了网络创业界。现在,许多有趣的数据库系统都与#No SQL hashtag相关,并且它被重新定义为NOT Only SQL [4]
在NO SQL数据库的情况下,有几个驱动因素,包括:
1、比关系型数据库更好的扩展性,包括更大的数据集以及吞吐量。
2、更好的开源而不是商业化的。
3、关系模型不支持的特定查询操作
4、对关系模型的schema的限制感到沮丧,对更动态和更具代表性数据模型的渴望 [5]
不同的应用程序有不同的需求,对于一个用例来说,最好的技术选择可能与另一个用例的最佳选择不同。因此,在可预见的将来,关系数据库将继续与广泛的非关系数据存储一起使用,这一概念有时被称为polyglot persistence[3]
03
The Object-Relational Mismatch
当今大多数应用程序开发都是在面向对象的编程语言中完成的,这导致了对SQL数据模型的常见批评:如果数据存储在关系表中,那么对象之间需要一个笨拙的转换层在应用代码和关系型模型诸如表,行和列之间。 模型之间的讨论有时被称为impedance mismatch.( 从电子产品中借用的术语。每个电路的输入和输出都有一定的阻抗(对交流电流的阻抗)。当你将一个电路的输出连接到另一个电路的输入时,如果两个电路的输出和输入阻抗匹配,连接上的power transfer就会最大化。阻抗不匹配会导致信号反射和其他问题)
对象-关系映射(ORM)框架,如Active Record和Hibernate 减少这个翻译层所需的样板代码量。但它们不能完全隐藏这两个模型之间的差异。
图2-1
例如,上图说明了在关系模式中如何表示一份简历(概要文件中的链接)。整个概要文件可以通过一个惟一的标识符user_id来标识( be identified), 像first_name和last_name这样的字段恰好显示为每一个用户,因此它们可以被建模为users表上的列。 然而,大多数人在他们的职业(职位)中有不止一份工作,而且人们可能会有大量的教育时期和任何数量的联系信息, 从用户到这些项目之间有一对多的关系,可以用不同的方式表示:
1、在传统的SQL模型(在SQL:1999之前)中,最常见的标准化 的 表现是将位置、教育和联系信息放在分隔表中,并将外键引用放在users表中,如图所示。
2、后来版本的SQL标准增加了对结构化数据类型和xml数据的支持;这允许将多值数据存储在单个行中,并支持在这些文档中查询和索引。这些特性通过Oracle、IBM DB2、MS SQL Server和Post‐gre SQL(6、7)进行了不同程度的移植。JSON数据类型也由几个数据库支持,包括ibm DB2、SQL和Postgre SQL [8]
3、第三种选择是将work、教育和联系信息作为JSON或XML document进行编码,将其存储在数据库的文本列上,并让应用程序对其结构和内容进行优先处理。在这个设置中,通常不能使用database to查询在编码列内的值。
对于像resume这样的数据结构,它通常是一个自包含的文档,JSON representation可能非常合适:参见示例2-1。JSON具有比XML简单得多的吸引力。面向文档的数据库如Mongo DB[9]、Rethink DB[10]、Couch DB[11]和Espresso[12]支持这个数据模型。
Example 2-1. Representing a Linked In profile as a JSON document
{
"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"
}
}
04
JSON
一些开发人员认为,JSON模型减少了应用程序代码和存储层之间的阻抗不匹配(impedance mismatch)。但是,正如我们将在第4章中看到的,JSON作为一种数据编码格式也存在一些问题。缺乏schema常常被认为是一种优势。 我们将在第39页的“Schema flexibility in the document model”中讨论这个问题。
JSON表示具有比图2-1中多表模式更好的局部性。 如果您想在关系数据库示例中获取一个概要文件,您需要执行多个查询(通过user_id查询每个表),或者在users表及其附属表之间执行一个混乱的多路连接。在JSON代表中,所有相关信息都在一个地方,一个查询就足够了。
从用户配置文件到用户位置、教育历史和联系信息的一对多关系意味着数据中的树结构,而json表示使树结构显式(见图2-2)
图2-2
05
Many-to-One and Many-to-Many Relationships
在前一节中,以图2-1为例,区域id和行业id被指定为IDs,而不是纯文本字符串“Greater Seattle Area”和“Philanthropy”。思考下这是为什么?
如果用户界面有需要输入区域和行业的文本字段,那么将它们存储为纯文本字符串是有意义的。 同时,将地理位置信息抽取出来组成一张表也是有好处的:
1、有助于保持一致的风格和拼写
2、避免歧义 (e.g., if there are several cities with the same name)
3、易于更新-the name is stored in only one place, so it is easy to update across the board if it ever needs to be changed (e.g., change of a city name due topolitical events)
4、本地化支持—when the site is translated into other languages, the stand‐ardized lists can be localized, so the region and industry can be displayed in theviewer’s language
5、方便更好的查询—e.g., a search for philanthropists in the state of Washington can match this profile, because the list of regions can encode the fact that Seattle is inWashington (which is not apparent from the string "Greater Seattle Area")
是否存储ID或文本字符串主要考虑的是重复的问题。 当您使用ID时,对人类有意义的信息(例如“Philanthropy慈善”)只存储在一个地方,所有引用的信息都使用一个ID(在数据库中只有这个ID)。 当您直接存储文本时,您将在每个使用它的记录中复制具有人类意义的信息。 使用ID的优点是,因为它对人类没有意义,所以即使它标识的信息发生了变化,它也不需要改变。而任何对人类有意义的事情都可能在未来的某个时候发生变化——如果这些信息被复制,所有多余的副本都需要更新。 这就会导致写过多的开销,并且会出现不一致的风险(有些信息会被更新,而有些则没有更新)。消除这种重复是数据库标准化的关键思想。
不幸的是对数据进行规范化需要多对一的关系(many-to-one )例如,许多人生活在同一个区域,许多人在同一个行业工作等,此时人与区域,人与行业都是多对一关系,这种多对一关系并不适合document model.而在关系型数据库中通常通过ID引用其他表中的行,因为在关系型数据库中join很容易。但是在document model中join操作对于一对多(one-to-many)的树形结构并不是必须的,并且对Join的支持非常差。
如果数据库本身不支持JOIN,那么就需要在应用端代码中通过多次查询数据库模拟JOIN操作(在上面提到的这种情况下,区域和行业列表可能很小,你可以吧他们报错在内存中,但这这样做相当于吧JOIN的工作从数据库中转移到应用端代码中了)
此外,即使应用的初始版本很适合无连接的document model,但是随着应用程序功能的不断添加,数据会倾向于变得更加具有关联性
05
Relational Versus Document Databases Today
当比较关系型数据与document数据库是有很多需要考虑的地方,包括他们的容错性(see Chapter 5),并发处理能力(see Chapter 7)。这里我们仅仅对数据模型进行对比。
document模型的最大优势是schema灵活,由于locality具有更好的性能,同时对于一些应用,他更接近与一些应用使用的数据结构。而关系型数据库的优势是提供JOIN和更好的对多对一,以及多对多的支持。
Which data model leads to simpler application code?
如果你的应用的数据结构类似文档(例如一个一对多的树型结构,且通常一次加载整个树)那么document将非常合适;而关系技术将一个类似文档的结构撕裂成几个碎片化的表,会导致复杂的schema和复杂的应用程序代码。
文档数据库也有限制,例如你不能直接引用文档中未定义的项目,而是需要这样说“用户251的职位列表中第二个职位”(很像层级模型中的访问路径),然而只要文档没有太深的嵌套,这通常不是问题。
而文档数据库对JOIN的支持不足,可能是问题,也可能不是问题,这主要取决于应用。例如利用文档数据库记录某个时间点发生的事件并分析的应用中,可能不需要多对多关系。然而如果你的应用中确实需要多对多关系,那么document数据库就不那么吸引人了。它可能导致需要使用非常规的手段来实现JOIN操作,此外应用程序也需要添加额外的代码来保证数据一致性:通过向数据库发送多个请求可以在应用端实现JOIN操作,但是这样会将复杂性转移到应用程序中,同时通常比在数据库汇总专门执行JOIN的代码要慢。即在这种情况下,会导致应用程序更加复杂以及更糟糕的性能。
一般来说,无法肯定哪个数据库一定会导致应用程序更加复杂,它主要取决于数据项之间的关系类型,对于高度互联的数据,文档数据库是笨拙的,而关系型数据库是有效的,图数据库是更加自然的。
06
Schema flexibility in the document model
大多数的document数据库以及支持JSON的关系型数据库不会对document中的数据进行任何强制的schema,在关系型数据库汇总支持XML时通常带有可选的schema验证。没有schema时任意的key和value都可以插入到document中,同时在读取数据时客户端对数据没有任何保证。
document通常也被称为schemaless,这没称呼有一些误导的意思,因为读取数据的代码通常采用某种结构,例如是一个隐式的schema,只是没有被数据库强制执行[20]。一个更准却的词是:schema-on-read(数据的结构时隐式的,只有当读取数据时才使用该结构去解析)。与之相应的 是schema-on-write(通常在关系型数据库中被采用,schema是显示的,数据库会确保所有的数据都符合schema)
Schema-on-read类似于编程语言中的动态类型检查,相反,Schema-on-write就是静态类型检查。正如对于静态类型检查和动态类型检查有很大争论一样 ,数据库中schema的实现也是一个有很大争议的额话题,没有对错。
当应用程序想要更改他的数据格式时,这两种模式的差异将会非常明显;假如,当前你正在将每个用户的全名存储在一个字段中,然而不久之后你希望姓和名分开存储,在document数据库中,你需要开始一个新的document用来写first name,同时在应用程序中当读取老的数据时需要进行如下处理:
```
if (user && user.name && !user.first_name) {
// Documents written before Dec 8, 2013 don't have first_name
}
```
而另一方面,在静态类型schema的数据库中,你需要进行迁移:
ALTER TABLE users ADD COLUMN first_name text;
UPDATE users SET first_name = split_part(name, ' ', 1); -- Postgre SQL
UPDATE users SET first_name = substring_index(name, ' ', 1); -- My SQL
schema修改的代价是需要停机时间,这个代价是完全不值得的,大多数的关系型数据在执行 ALTER TABLE语句的耗时约在几秒内,MYsql是一个明显的例外, 它可以在ALTER table上复制整个表,这意味着在修改一个大型表时,可能需要几分钟甚至几个小时的停机时间——尽管有各种各样的工具在这个限制下工作。
在大表上运行UPDATE语句可能会在任何数据库上都很慢,因为每一行都需要重写。如果这是不可接受的,那么应用程序可以将first_name设置为NULL,并在读取时填充它,就像使用文档数据库一样,
但是在schema-on-read模式下是危险的,如果一个集合中的所有元素因为一些原因(例如数据是多样的)导致结构并不是一致,例如:
有许多不同类型的对象,将每种类型的对象放到各自的表中是不实际的
数据的结构是由外部系统决定的,而这些系统是您所控制的,并且随时可能发生变化。
在这种情况下,一个schema可能会过大于功,而schemaless的记录则是一个更自然的数据模型。 但是,如果所有的记录都被期望具有相同的结构,那么schema是用来记录和执行结构的有用机制。我们将在第4章中详细讨论模式和模式演化。
References
[1] Edgar F. Codd: “A Relational Model of Data for Large Shared Data Banks,” Com‐munications of the ACM, volume 13, number 6, pages 377–387, June 1970. doi:10.1145/362384.362685
[2] Michael Stonebraker and Joseph M. Hellerstein: “What Goes Around ComesAround,” in Readings in Database Systems, 4th edition, MIT Press, pages 2–41, 2005.ISBN: 978-0-262-69314-1
[3] Pramod J. Sadalage and Martin Fowler: No SQL Distilled. Addison-Wesley, August2012. ISBN: 978-0-321-82662-6
[4] Eric Evans: “No SQL: What’s in a Name?,” blog.sym-link.com, October 30, 2009.
[6] Michael Wagner: SQL/XML:2006 – Evaluierung der Standardkonformität ausge‐wählter Datenbanksysteme. Diplomica Verlag, Hamburg, 2010. ISBN:978-3-836-64609-3
[7] “XML Data in SQL Server,” SQL Server 2012 documentation, technet.micro‐soft.com, 2013.
[8] “Postgre SQL 9.3.1 Documentation,” The Postgre SQL Global DevelopmentGroup, 2013.
[9] “The Mongo DB 2.4 Manual,” Mongo DB, Inc., 2013.
[10] “Rethink DB 1.11 Documentation,” rethinkdb.com, 2013.
[12] Lin Qiao, Kapil Surlaker, Shirshanka Das, et al.: “On Brewing Fresh Espresso:Linked In’s Distributed Data Serving Platform,” at ACM International Conference onManagement of Data (SIGMOD), June 2013.
[13] Rick Long, Mark Harrington, Robert Hain, and Geoff Nicholls: IMS Primer.IBM Redbook SG24-5352-00, IBM International Technical Support Organization,January 2000.
[14] Stephen D. Bartlett: “IBM’s IMS—Myths, Realities, and Opportunities,” TheClipper Group Navigator, TCG2013015LI, July 2013.
[15] Sarah Mei: “Why You Should Never Use Mongo DB,” sarahmei.com, November11, 2013.
未完待续
DataBases
图/来源Adobe Stock images
文/翻译
一
只
程序猿
我是雨钓
一只被硅基虫子调戏的
碳基猿
文章来源《Designing Data-Intensive Applications》翻译
领取专属 10元无门槛券
私享最新 技术干货