反正常用的硬盘的储存结构翻来翻去也就是在B树上折腾,或者说利用数据的排序性质做折腾

我们把索引的排序+写入的数据的排序拆开来看,做排列组合

主键索引将索引字段排序写入+数据按主键id排序写入=MySQL InnoDB引擎

索引排序写入+数据不排序写入=MySQL MyISAM引擎上建立索引

下面在普及下NoSQL里的LSM Tree

LSM Tree相当于多颗b树一起组成一颗树

主键索引将索引字段排序写入+数据按主键id排序写入+LSM=Hbase/Cassandra

索引排序写入+LSM+数据根据offset读取写入=Mongo

ES没研究过,不过索引上肯定也是LSM树

然后以下是我做的一个benchmark

可以看出两个已排序的树的Join的开销其实很低,那么只要在LSM Tree下的每颗B树上带上一个时间戳,那么通过多棵树的Join+时间戳新的数据覆盖时间戳旧的数据,然后保证每颗B树不可变,要变也是通过MergeJoin的方式将两颗B树合并成一颗更大的B树,然后内存里面维护一颗可变的排序树,当这颗树到达一个阈值时(一般32M),直接刷入硬盘,这样就能做到每次insert只读取内存里的数据,不读取硬盘上的数据,从而达到只要NoSQL的可变树缓存没击穿,CPU没到100%,配合索引字段的分区写入多集群,写入性能就没有瓶颈的效果,相应的,这样来说读取的时候有几棵树就要读取几次,其中读取每颗B树的性能可以视作和MySQL读取B树的性能一致,其他的性能差距就是在缓存策略上的差距罢了,配合合理的设计和参数调整能够规避很多问题

然后是针对某个id查询的问题,一般来说NoSQL会取你的RowKey做布隆过滤器,能够筛掉很大一部分的没有此id的B树不去读取,这种情况查询id性能和MySQL差不多,但是如果这个id是在长时间一直update的,那么布隆过滤器有和没有是一样的了,有几个B树包含了此id就慢几倍

所以可以这么看

HBase这种是按范围读写+MySQL写入能力跟不上时使用的数据库

ES可以看作采用了HBase类似的储存结构,但是自动帮你从文本中提取出索引字段的数据库,省了你自己维护全文索引的各种坑,硬要当HBase那样用估计也可以,但是人家不是为这种情景做设计的,估计有或多或少的设计上根本不会去想的坑在里面,比如一致性,可用性之类的问题,真要用前提是有人帮你踩过坑,否则还是老老实实用HBase

MySQL这种是你写入完全不是什么问题的时候,读多于写,要并发,要事务,要灵活,要快速开发,要容易运维,关系型数据库完爆NoSQL