每个程序员都有一个成为架构师的梦想,奈何手里无枪无法点燃心中奇梦。本系列文章分享如何让你手里有枪,只要努力,技术的梦想一定能实现,这应该是众多梦想中离地表最近的一个。
关系数据库经过几十年的发展后已经非常成熟,强大的SQL功能和ACID的属性,使得关系数据库广泛应用于各式各样的系统中,但是关系数据库存在如下缺点:
针对上述问题,诞生了不同的NoSQL解决方案,这些方案与关系数据库相比,在某些应用场景下表现更好。NoSQL作为SQL的一个有力补充,NoSQL != No SQL,而是NoSQL = Not Only SQL。
常见的NoSQL方案分为4类:
K-V存储的全称是Key-Value存储,其中Key是数据的标识,和关系数据库中的主键含义一样,Value就是具体的数据。
Redis是K-V存储的典型代表,它是一款开源(基于BSD许可)的高性能K-V缓存和存储系统。
Redis的Value是具体的数据结构,包括string、hash、list、set、sorted set、bitmap和hyperloglog,所以常常被称为数据结构服务器。
以List数据结构为例,Redis提供了下面这些典型的操作:
以上这些功能,如果用关系数据库来实现,就会变得很复杂。
例如,LPOP操作是移除并返回key对应的list的第一个元素。
如果用关系数据库来存储,为了达到同样目的,需要进行下面的操作:
可以看出关系数据库的实现很麻烦,而且需要进行多次SQL操作,性能很低。
Redis的缺点主要体现在并不支持完整的ACID事务,Redis虽然提供事务功能,Redis的事务只能保证隔离性和一致性(I和C),无法保证原子性和持久性(A和D)。
虽然Redis并没有严格遵循ACID原则,但实际上大部分业务也不需要严格遵循ACID原则。
以上面的微博关注操作为例,即使系统没有将A加入B的粉丝列表,其实业务影响也非常小,因此我们在设计方案时,需要根据业务特性和要求来确定是否可以用Redis,而不能因为Redis不遵循ACID原则就直接放弃。
为了解决关系数据库schema带来的问题,文档数据库应运而生。
文档数据库最大的特点就是no-schema,可以存储和读取任意的数据。
目前绝大部分文档数据库存储的数据格式是JSON(或者BSON),因为JSON数据是自描述的,无须在使用前定义字段,读取一个JSON中不存在的字段也不会导致SQL那样的语法错误。
文档数据库的no-schema特性,给业务开发带来了几个明显的优势:
例如,我们设计一个用户管理系统,用户的信息有ID、姓名、性别、爱好、邮箱、地址、学历信息。其中爱好是列表(因为可以有多个爱好);地址是一个结构,包括省市区楼盘地址;学历包括学校、专业、入学毕业年份信息等。
如果我们用关系数据库来存储,需要设计多张表,包括基本信息(列:ID、姓名、性别、邮箱)、爱好(列:ID、爱好)、地址(列:省、市、区、详细地址)、学历(列:入学时间、毕业时间、学校名称、专业), 而使用文档数据库,一个JSON就可以全部描述
使用JSON来描述数据,比使用关系型数据库表来描述数据方便和容易得多,而且更加容易理解。
文档数据库的这个特点,特别适合电商和游戏这类的业务场景。以电商为例,不同商品的属性差异很大。例如,冰箱的属性和笔记本电脑的属性差异非常大。
文档数据库no-schema的特性带来的这些优势也是有代价的,最主要的代价就是不支持事务。
例如,使用MongoDB来存储商品库存,系统创建订单的时候首先需要减扣库存,然后再创建订单。这是一个事务操作,用关系数据库来实现就很简单,但如果用MongoDB来实现,就无法做到事务性。
异常情况下可能出现库存被扣减了,但订单没有创建的情况。因此某些对事务要求严格的业务场景是不能使用文档数据库的。
文档数据库另外一个缺点就是无法实现关系数据库的join操作。
例如,我们有一个用户信息表和一个订单表,订单表中有买家用户id。如果要查询“购买了苹果笔记本用户中的女性用户”,用关系数据库来实现,一个简单的join操作就搞定了;
而用文档数据库是无法进行join查询的,需要查两次:一次查询订单表中购买了苹果笔记本的用户,然后再查询这些用户哪些是女性用户。
列式数据库是按照列来存储数据的数据库,与之对应的传统关系数据库被称为“行式数据库”,因为关系数据库是按照行来存储数据的。
关系数据库按照行式来存储数据,主要有以下几个优势:
我们可以看到,行式存储的优势是在特定的业务场景下才能体现,如果不存在这样的业务场景,那么行式存储的优势也将不复存在,甚至成为劣势。
列式数据库的优势:
列式数据库的劣势:
基于上述列式存储的优缺点,一般将列式存储应用在离线的大数据分析和统计场景中,因为这种场景主要是针对部分列单列进行操作,且数据写入后就无须再更新删除。
传统的关系型数据库通过索引来达到快速查询的目的,但是在全文搜索的业务场景下,索引也无能为力,主要体现在:
全文搜索引擎的技术原理被称为“倒排索引”(Inverted index),也常被称为反向索引,是一种索引方法,其基本原理是建立单词到文档的索引。 之所以被称为“倒排”索引,是和“正排“索引相对的,“正排索引”的基本原理是建立文档到单词的索引。
举一个简单的样例来说明这两种索引的差异: 假设我们有一个技术文章的网站,里面收集了各种技术文章,用户可以在网站浏览或者搜索文章。 正排索引示例:
文章ID | 文章名称 | 文章内容 |
1 | 菜鸟到架构师之路之架构设计的原则 | 具体内容是:XXX,内容包含:编程、设计、架构师 |
2 | 程序员职业发展规划 | 具体内容是:XXX,内容包含:程序员成长、编程、设计、架构师 |
3 | 程序员成长建议 | 具体内容是:XXX,内容包含:程序员成长、架构师 |
正排索引适用于根据文档名称来查询文档内容。例如,用户在网站上单击了“程序员职业发展规划”,网站根据文章标题查询文章的内容展示给用户。
倒排索引示例:
关键词 | 文档ID列表 |
编程 | 1,2 |
架构师 | 1,2,3 |
程序员成长 | 2,3 |
倒排索引适用于根据关键词来查询文档内容。例如,用户只是想看“架构师”相关的文章,网站需要将文章内容中包含“架构师”一词的文章都搜索出来展示给用户。
全文搜索引擎的索引对象是单词和文档,而关系数据库的索引对象是键和行,两者的术语差异很大,不能简单地等同起来。
因此,为了让全文搜索引擎支持关系型数据的全文搜索,需要做一些转换操作,即将关系型数据转换为文档数据。 目前常用的转换方式是将关系型数据按照对象的形式转换为JSON文档,然后将JSON文档输入全文搜索引擎进行索引。
全文搜索引擎能够基于JSON文档建立全文索引,然后快速进行全文搜索。以Elasticsearch为例,其索引基本原理如下:
Elastcisearch是分布式的文档存储方式。它能存储和检索复杂的数据结构——序列化成为JSON文档——以实时的方式。 在Elasticsearch中,每个字段的所有数据都是默认被索引的。即每个字段都有为了快速检索设置的专用倒排索引。 而且,不像其他多数的数据库,它能在相同的查询中使用所有倒排索引,并以惊人的速度返回结果。
| 留言与评论(共有 0 条评论) “” |