高性能nosql
Posted 07zhywjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高性能nosql相关的知识,希望对你有一定的参考价值。
--------------------------------------------------------------------------------------------------------
即使是同类商品也有不同的属性。例如,LCD 和 LED 显示器,两者有不同的参数指标。这种业务场景如果使用关系数据库来存储数据,就会很麻烦,而使用文档数据库,会简单、方便许多,扩展新的属性也更加容易。
文档数据库 no-schema 的特性带来的这些优势也是有代价的,最主要的代价就是不支持事务。例如,使用 MongoDB 来存储商品库存,系统创建订单的时候首先需要减扣库存,然后再创建订单。这是一个事务操作,用关系数据库来实现就很简单,但如果用 MongoDB 来实现,就无法做到事务性。异常情况下可能出现库存被扣减了,但订单没有创建的情况。因此某些对事务要求严格的业务场景是不能使用文档数据库的。
文档数据库另外一个缺点就是无法实现关系数据库的 join 操作。例如,我们有一个用户信息表和一个订单表,订单表中有买家用户 id。如果要查询“购买了苹果笔记本用户中的女性用户”,用关系数据库来实现,一个简单的 join 操作就搞定了;而用文档数据库是无法进行 join 查询的,需要查两次:一次查询订单表中购买了苹果笔记本的用户,然后再查询这些用户哪些是女性用户。
列式数据库
顾名思义,列式数据库就是按照列来存储数据的数据库,与之对应的传统关系数据库被称为“行式数据库”,因为关系数据库是按照行来存储数据的。
关系数据库按照行式来存储数据,主要有以下几个优势:
业务同时读取多个列时效率高,因为这些列都是按行存储在一起的,一次磁盘操作就能够把一行数据中的各个列都读取到内存中。
能够一次性完成对一行中的多个列的写操作,保证了针对行数据写操作的原子性和一致性;否则如果采用列存储,可能会出现某次写操作,有的列成功了,有的列失败了,导致数据不一致。
我们可以看到,行式存储的优势是在特定的业务场景下才能体现,如果不存在这样的业务场景,那么行式存储的优势也将不复存在,甚至成为劣势,典型的场景就是海量数据进行统计。例如,计算某个城市体重超重的人员数据,实际上只需要读取每个人的体重这一列并进行统计即可,而行式存储即使最终只使用一列,也会将所有行数据都读取出来。如果单行用户信息有 1KB,其中体重只有 4 个字节,行式存储还是会将整行 1KB 数据全部读取到内存中,这是明显的浪费。而如果采用列式存储,每个用户只需要读取 4 字节的体重数据即可,I/O 将大大减少。
除了节省 I/O,列式存储还具备更高的存储压缩比,能够节省更多的存储空间。普通的行式数据库一般压缩率在 3:1 到 5:1 左右,而列式数据库的压缩率一般在 8:1 到 30:1 左右,因为单个列的数据相似度相比行来说更高,能够达到更高的压缩率。
同样,如果场景发生变化,列式存储的优势又会变成劣势。典型的场景是需要频繁地更新多个列。因为列式存储将不同列存储在磁盘上不连续的空间,导致更新多个列时磁盘是随机写操作;而行式存储时同一行多个列都存储在连续的空间,一次磁盘写操作就可以完成,列式存储的随机写效率要远远低于行式存储的写效率。此外,列式存储高压缩率在更新场景下也会成为劣势,因为更新时需要将存储数据解压后更新,然后再压缩,最后写入磁盘。
基于上述列式存储的优缺点,一般将列式存储应用在离线的大数据分析和统计场景中,因为这种场景主要是针对部分列单列进行操作,且数据写入后就无须再更新删除。
全文搜索引擎
传统的关系型数据库通过索引来达到快速查询的目的,但是在全文搜索的业务场景下,索引也无能为力,主要体现在:全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引的数量会非常多。全文搜索的模糊匹配方式,索引无法满足,只能用 like 查询,而 like 查询是整表扫描,效率非常低。
我举一个具体的例子来看看关系型数据库为何无法满足全文搜索的要求。假设我们做一个婚恋网站,其主要目的是帮助程序员找朋友,但模式与传统婚恋网站不同,是“程序员发布自己的信息,用户来搜索程序员”。程序员的信息表设计如下:
ID 姓名 性别 地点 单位 爱好 语言 自我介绍
1 多隆 男 北京 猫厂 写代码、旅游、马拉松 Java、C++、php 技术专家,简单,为人热情
2 如花 女 上海 鹅厂 旅游、美食、唱歌 PHP、Java 美女如花,风华绝代,貌美如花
3 小宝 男 广州 熊厂 泡吧、踢球 Python、Go、C 我是一匹来自北方的狼
我们来看一下这个简单业务的搜索场景:
美女 1:听说 PHP 是世界上最好的语言,那么 PHP 的程序员肯定是钱最多的,而且我妈一定要我找一个上海的。
美女 1 的搜索条件是“性别 + PHP + 上海”,其中“PHP”要用模糊匹配查询“语言”列,“上海”要查询“地点”列,如果用索引支撑,则需要建立“地点”这个索引。
美女 2:我好崇拜这些技术哥哥啊,要是能找一个鹅厂技术哥哥陪我旅游就更好了。
美女 2 的搜索条件是“性别 + 鹅厂 + 旅游”,其中“旅游”要用模糊匹配查询“爱好”列,“鹅厂”需要查询“单位”列,如果要用索引支撑,则需要建立“单位”索引。
美女 3:我是一个“女程序员”,想在北京找一个猫厂的 Java 技术专家。
美女 3 的搜索条件是“性别 + 猫厂 + 北京 + Java + 技术专家”,其中“猫厂 + 北京”可以通过索引来查询,但“Java”“技术专家”都只能通过模糊匹配来查询。
帅哥 4:程序员妹子有没有漂亮的呢?试试看看。
帅哥 4 的搜索条件是“性别 + 美丽 + 美女”,只能通过模糊匹配搜索“自我介绍”列。
以上只是简单举个例子,实际上搜索条件是无法列举完全的,各种排列组合非常多,通过这个简单的样例我们就可以看出关系数据库在支撑全文搜索时的不足。
1. 全文搜索基本原理
全文搜索引擎的技术原理被称为“倒排索引”(Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,其基本原理是建立单词到文档的索引。之所以被称为“倒排”索引,是和“正排“索引相对的,“正排索引”的基本原理是建立文档到单词的索引。我们通过一个简单的样例来说明这两种索引的差异。
假设我们有一个技术文章的网站,里面收集了各种技术文章,用户可以在网站浏览或者搜索文章。
正排索引示例:
文章 ID 文章名称 文章内容
1 敏捷架构设计原则 省略具体内容,文档内容包含:架构、设计、架构师等单词
2 Java 编程必知必会 省略具体内容,文档内容包含:Java、编程、面向对象、类、架构、设计等单词
3 面向对象葵花宝典是什么 省略具体内容,文档内容包含:设计、模式、对象、类、Java 等单词
(注:文章内容仅为示范,文章内容实际上存储的是几千字的内容。)
正排索引适用于根据文档名称来查询文档内容。例如,用户在网站上单击了“面向对象葵花宝典是什么”,网站根据文章标题查询文章的内容展示给用户。
倒排索引示例:
单词 文档 ID 列表
架构 1,2
设计 1,2,3
Java 2,3
(注:表格仅为示范,不是完整的倒排索引表格,实际上的倒排索引有成千上万行,因为每个单词就是一个索引。)
倒排索引适用于根据关键词来查询文档内容。例如,用户只是想看“设计”相关的文章,网站需要将文章内容中包含“设计”一词的文章都搜索出来展示给用户。
2. 全文搜索的使用方式
全文搜索引擎的索引对象是单词和文档,而关系数据库的索引对象是键和行,两者的术语差异很大,不能简单地等同起来。因此,为了让全文搜索引擎支持关系型数据的全文搜索,需要做一些转换操作,即将关系型数据转换为文档数据。
目前常用的转换方式是将关系型数据按照对象的形式转换为 JSON 文档,然后将 JSON 文档输入全文搜索引擎进行索引。我同样以程序员的基本信息表为例,看看如何转换。
将前面样例中的程序员表格转换为 JSON 文档,可以得到 3 个程序员信息相关的文档,我以程序员 1 为例:
{
"id": 1,
" 姓名 ": " 多隆 ",
" 性别 ": " 男 ",
" 地点 ": " 北京 ",
" 单位 ": " 猫厂 ",
" 爱好 ": " 写代码,旅游,马拉松 ",
" 语言 ": "Java、C++、PHP",
" 自我介绍 ": " 技术专家,简单,为人热情 "
}
全文搜索引擎能够基于 JSON 文档建立全文索引,然后快速进行全文搜索。以 Elasticsearch 为例,其索引基本原理如下:Elastcisearch 是分布式的文档存储方式。它能存储和检索复杂的数据结构——序列化成为 JSON 文档——以实时的方式。
在 Elasticsearch 中,每个字段的所有数据都是默认被索引的。即每个字段都有为了快速检索设置的专用倒排索引。而且,不像其他多数的数据库,它能在相同的查询中使用所有倒排索引,并以惊人的速度返回结果。今天整理了为了弥补关系型数据库缺陷而产生的 NoSQL 技术,希望对大家所帮助。
以上是关于高性能nosql的主要内容,如果未能解决你的问题,请参考以下文章