SQL和NoSQL的分析
基本概念
SQL和NoSQL是一个很基本的概念,相信很多人都听说过,网上也有很多文章来介绍两者的对比。那么什么是SQL,什么又是NoSQL呢?
所谓的SQL(Structured Query Language),就是我们俗称的关系型数据库。它是基于关系模型来组织数据的数据库。一般来说,使用预定义的schema来决定数据的结构。所有数据都必须遵循同样的结构,这也就意味着你很难对数据的结构进行改变。
NoSQL(Not Only SQL),从它的名字我们可以很容易发现,它是在SQL后出现的,其实早期它只是社区讨论的一个tag,一步步演变到了今天用来泛指非关系型数据库。和SQL相对的,它是基于动态Schema的非结构化数据,它可以是基于文档的,键值对,wide column或者基于图的。
可以说NoSQL的产生就是因为在某些情况下SQL已经无法满足现如今的一些场景,比如超大数据等。但是,需要承认的是SQL目前还是主流企业使用的技术,其也是可以满足几乎绝大多数业务需求的。强调这一点的原因是,很多学生或者没有太多业界经验的人会下意识的觉得NoSQL更好,优先考虑NoSQL,其实不然,大多数情况我们还是应该倾向于SQL的设计,当然如何进行选择我们会在后文中详细讨论。
实例分析
在了解了相关的基本概念之后,我们来看一个具体的例子进行分析,这样才能对两者有一个感性的认识。就拿比尔盖茨的LinkedIn的页面来简单分析吧。就这样一个简单的页面,我们在数据库中该如何设计呢?

首先来看看关系型数据库中的表格设计,简单设计如下图所示。这里值得一提的就是我们如何保存城市相关的信息,我们这里使用的是id来进行保存而不是一个字符来保存,这样做有以下好处:
- 很方便进行修改,因为所有的城市名字都保存在一个地方,比如哪一天Seattle改名字叫Seattle2了,我们只要修改一个表格中的一行数据就可以了,而不需要把所有的记录都进行修改。
- 很容易进行本地化处理,比如说我们的页面需要在中国现实,那么Seattle就可以显示成“西雅图”,这样的设计就很容易做。
- 防止拼写错误,假如我们让用户来输入地址,那么就有可能这样地址被写成Saettle之类的,从而导致一系列问题。
- 更易于搜索,比如我们搜索华盛顿州的人,那么这样的层级关系就很容易被发现。而只保存字符就不利于这样的搜索。

其实像上面这种例子,使用面向文档的数据结构也蛮合适的,比如JSON格式的设计可以如下所示,相比于上面关系型数据库设计,这种设计在读取方面有很大的优势,我们不需要去做多个join来获取job和education之类的信息,只需要读取相关的user保存的信息就能得到我们所想要的信息。

SQL和NoSQL的比较
Schema的设计
如我们上面例子中所示,关系型数据库会把数据保存在多个表格中,这些表格相互之间是有关系的。表格是由行和列来组成的,每行就是一个数据记录,每列保存一个特定类型的数据,而且表格中的每行数据的列都是相同的(可以是null)。
而NoSQL则不同,总得来说NoSQL可以分为以下几个种类:
- 基于文档的数据库。这种数据库是基于类似JSON的文档来保存数据的。我们可以认为它虽然没有定义表结构,但是可以像定义了表结构一样使用它。它也支持一些复杂的查询条件,相比关系型数据库除了事务处理和JOIN不支持外,其他的各项功能都支持得很好。
- 基于键值的数据库。这个数据库存储的就是键值对,他们可以是各种各样的格式,可以是字符串也可以是复杂的值。它的特点就是处理的速度很快,它通过把键保存成特殊的index,从而达到快速查询的目的。它一般可以分为临时型,永久型和两者兼具这三种。所谓临时型就是相关的键值都是保存在内存中,所以读取速度很快,相应的问题就是他数据很容易丢失,不是永久保存。而永久型的则相反,它的数据是永久保存的,也就是保存到磁盘中,相对来说就会受到磁盘IO的限制,从而读写的速度不是那么快。而两者兼具型则是兼具两者的优点,首先会把数据保存在内存中,从而达到快速访问的目的。同时又会根据一定的算法把数据保存到磁盘中,这样就可以保证最终的数据永久性了。
- 基于宽列的数据库。这种数据库和关系型数据库比较类似,只是它每行的列数目是动态的,可以逻辑上把这些列组成不同的列家族。
- 基于图的数据库。它使用的节点来存储数据实体,使用边来储存之间的关系。这种数据库在关系性比较强的数据或者推荐引擎中使用得比较多。
速度
在大多数情况下,这两种数据库的速度性能上来比较并没有特别的差别。但是在一些比较复杂的情景下还是稍有不同的。
我们上文提到关系型数据库会使用类似保存ID,然后JOIN的方式来存储数据,这当然有很多优点,就像我们上面提到的一样,方便修改啊之类的。但是相应的代价就是我们每次查询的时候都需要JOIN这些表格。而当JOIN很多表格的时候,必然会产生性能的损失,而NoSQL则可以很好的克服这个问题。
NoSQL并不太在意相应数据存储空间,它一切以查询结果为导向。因此其查询的速度显然也就会很快了。
扩展
一般来说,SQL的扩展都是垂直扩展,也就是加大CPU,加大内存,加大磁盘空间等来解决性能瓶颈。这种扩展的方式一方面很容易就达到性能的瓶颈,另一方面也可能最终没法满足日益增长的需求。现在SQL也开始在某种程度上支持横向的扩展,不过总得来说效果不是特别好。
NoSQL则是天然的支持横向扩展,也就是说当遇到性能问题的时候,你可以引入更多的机器来进行处理,这其实更符合现如今分布式系统的扩展趋势。显然在这方面,NoSQL是有先天的优势的。
指导原则
SQL和NoSQL最大的分别大概就是这里了,而且这个是原则性问题,一旦有了这方面的需求,其它的考量可能都需要靠边站了。
关系型数据库支持ACID:
- 原子性(Atomicity): 事务是要么不执行,要么就是执行一次。
- 一致性(Consistency):这个就是保证每次的执行总是完成的,如果发生问题,就会返回到最初的状态,不会处于一个中间的状态。
- 隔离性(Isolation):事务之间是完全独立的,不会相互影响。
- 持久性(Durability):当事务完成之后,它就会真正写到数据库中,不会因为各种意外丢失。
NoSQL则不完全支持ACID,相应的它使用的是CAP的理论:
- 一致性(Consistency):这里的一致性指的是不管你连接的是哪一个cluster(就是我们上文提到的横向扩展的机器),你得到的数据都是一致的。
- 可靠性(Availability):每一个请求都能得到回复,这看起来是一个很简单的要求,其实在业界是很难做到很高可靠性的,毕竟机器多了就会一直有各种各样的问题出现,比如磁盘坏了,网络不通了之类的,一般来说5个9的可靠性(99.999%)是大家想达到的目标。
- 分区容错性(Partition Tolerance):所谓的partition就是当一个节点不能和系统别的节点通信的时候。而这里的分区容错性就是当这种情况发生的时候,整个系统的运行不受任何影响。
另外一个重要的一点就是,NoSQL是无法做到这三点同时兼顾的,也就是说当partition发生的时候,你只能从一致性和可靠性中得到一个。也就是CP和AP之间需要做取舍。
如何选择
了解了上面的内容,我想在选择SQL还是NoSQL的时候应该有了基本的判断依据。假如你对ACID的要求很高,比如银行系统,那么毫无疑问,你需要选择SQL,因为NoSQL无法满足这样的要求。假如你的数据结构变换很少,那么也没有什么好的理由去选择NoSQL。
然而,假如你需要处理大量的非结构化的数据,NoSQL则是更好的选择。或者你需要高速的访问数据,而这些数据并不需要有很强的完整性保证,那么NoSQL也是一个不错的选择。
1 Response
[…] 在我们详细介绍之前,请大家一起先来回顾一下ACID的概念,你可以在我之前的这篇文章《SQL和NoSQL的分析》中找到详细的介绍,这里不再复述。 […]