一、hash:mysql
表明:nosql的redis/memcachedredis
本质为: 基于(内存中)的hash;sql
因此支持 随机 的增删查改,读写的时间复杂度O(1);数据库
可是没法支持顺序读写(注,这里指典型的hash,不是指如redis的基于跳表的zset的其余功能);缓存
基本效果:在不须要有序遍历时,最优nosql
二、磁盘查找树:memcached
表明:mysql性能
本质为:基于(磁盘的)顺序查找树,B树/B+树;优化
基本效果:支持有序遍历;但数据量很大后,随机读写效率低(缘由往下看);spa
三、lsmtree:
表明:hbase/leveldb/rocksdb
本质为: 实际落地存储的数据按key划分,造成有序的不一样的文件;
结合其“先内存更新后合并落盘”的机制,尽可能达到磁盘的写是顺序写,尽量减小随机写;
对于读,需合并磁盘已有历史数据和当前未落盘的驻于内存的更新,较慢;
基本效果:也能够支持有序增删查改;写速度大幅提升;读速度稍慢;
B树是一种平衡多路搜索树,B树与红黑树最大的不一样在于,B树的结点能够有多个子女,从几个到几千个。那为何又说B树与红黑树很类似呢?由于与红黑树同样,一棵含n个结点的B树的高度也为O(lgn),但可能比一棵红黑树的高度小许多,应为它的分支因子比较大。因此,B树能够在O(logn)时间内,实现各类如插入(insert),删除(delete)等动态集合操做。
B树的定义以下:
下图是一个M=4的4阶的B树:
B树的搜索:从根结点开始,对结点内的关键字(有序)序列进行二分查找,若是命中则结束,不然进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已是叶子结点;
B树的特性:
B+树是对B树的一种变形,与B树的差别在于:
以下图一个M=3 的B+树:
B+树的搜索:与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树能够在非叶子结点命中),其性能也等价于在关键字全集作一次二分查找;
B+的特性:
B树:多路搜索树,每一个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;全部关键字在整颗树中出现,且只出现一次,非叶子结点能够命中;
B+树:在B-树基础上,为叶子结点增长链表指针,全部关键字都在叶子结点中出现,非叶子结点做为叶子结点的索引;B+树老是到叶子结点才命中;
(1) B+tree的磁盘读写代价更低
B+tree的内部结点并无指向关键字具体信息的指针。所以其内部结点相对B树更小。若是把全部同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的须要查找的关键字也就越多。相对来讲IO读写次数也就下降了。
举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点须要2个盘快。而B+ 树内部结点只须要1个盘快。当须要把内部结点读入内存中的时候,B 树就比B+ 树多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。
(2)B+tree的查询效率更加稳定
因为非叶子结点并非最终指向文件内容的结点,而只是叶子结点中关键字的索引。因此任何关键字的查找必须走一条从根结点到叶子结点的路。全部关键字查询的路径长度相同,致使每个数据的查询效率至关。
(3)B树在提升了磁盘IO性能的同时并无解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就能够实现整棵树的遍历。并且在数据库中基于范围的查询是很是频繁的,而B树不支持这样的操做(或者说效率过低)。
大量的随机写,致使B族树在数据很大时,出现大量磁盘IO,致使速度愈来愈慢,lsmtree是怎么解决这个问题的:
一、尽量减小写磁盘次数;
二、即使写磁盘,也是尽量顺序写;
方法:
一、对数据,按key划分为若干level;
每个level对应若干文件,包括存在于内存中和落盘了的;
文件内key都是有序的,同级的各个文件之间,通常也有序
如leveldb/rocksdb,level0对应于内存中的数据(0.sst),后面的依次是一、二、三、...的各级文件(默认到level6级)
二、写时,先写对应于内存的最低level的文件;这是之因此写的快的一个重要缘由
存在于内存的数据,也是被持久化的以防丢失;
存在于内存的数据,到达必定大小后,被合并到下一级文件落盘;
三、落盘后的各级文件,也会按期进行排序加合并(compact),合并后数据进入下一层level;
这样的写入操做,大多数的写,都是对一个磁盘页顺序的写,或者申请新磁盘页写,而再也不是随机写
总结lsmtree的写为何快的两大缘由:
一、每次写,都是在写内存;
二、按期合并写入磁盘,产生的写都是按key顺序写,而不是随机查找key再写;
可见compact是个很重要的事情了,下面是基于lsmtree引擎的rocksdb的compact过程:
首先看一下rocksdb的各级文件组织形式:
而后,各级的每一个文件,内部都是按key有序,除了内存对应的level0文件,各级的内部文件之间,也是按key有序的;
这样,查找一个key,很方便二分查找(固然还有bloomfilter等的进一步优化)
再而后,每一级的数据到达必定阈值时,会触发排序归并,简单说,就是在两个level的文件中,把key有重叠的部分,合并到高层level的文件里
这个在lsmtree里,叫数据压缩(compact);
对于rocksdb,除了内存那个level0到level1的compact,其余各级之间的compact是能够并行的;一般设置较小的level0到level1的compact阈值,加快这一层的compact
良好的归并策略的配置,使数据尽量集中在最高层(90%以上),而不是中间层,这样有利于compact的速度;
另外,对于基于lsmtree的(rocksdb的)读,须要在各级文件中二分查找,磁盘IO也很多,此外还须要关注level0里的对于这个key的操做,比较明显的优化是,经过bloomfilter略掉确定不存在该key的文件,减小无谓查找;