起因
本周我在看一篇微信公众号文章的时候《现实生活中的算法》里面提到
老板每天正式营业前的“码货”本质就是在执行“排序算法”这个我觉得没什么问题。不过后面提到的这是因为驿站面积太小了,这里的算法是用时间换空间的算法。这句话,作者可能想说的是,无序的货物比较混乱,所以占更多空间。有序之后就有序,所以空间利用率更高了。所以老板是在用排序的时间来换空间利用率更高。但是这里的排序存在定义不清晰的问题,我多思考了下发现这个例子很有意思,所以我打算展开说下。
码货
作者的可能想的排序是快递和快递之间如果存在缝隙,那么可以排入一个更小的货物,这样可以达到更高的空间利用率。
但是我的理解不是这样的。以我知道的菜鸟驿站货物存放,一般来说,使用的是货柜->货架->快递的三层结构。一个快递驿站下会有多个货柜,一个货柜下有多个货架,一个货架下有多个快递,快递才是真正需要的东西。呃,那这玩意不就是B+树吗?这不就是InnoDB下的主键索引吗?老板在存入快递的时候,不就是在存入数据吗?你取货用的那个快递编码,不就是主键ID吗?它在一定程度上都是自增的。
所以用户上门取货效率也很低,总是找半天。如果这么理解老板的码货操作的话,那么用户就是在利用B+树查询加速了数据的读取速度。可以想象,菜鸟完全可以在不提供货柜号货架号的情况下,让客户去搜索他们自己的快递,因为快递上有他们的快递号标识,老板也能达到用时间换取空间的算法目的。
不,这不是最关键的,最关键的是,老板通过码货,使货物形成了B+树的数据结构,通过前期的一次写入时间投入,换取了后期无数次随机读取效率提升。
如何取快递
快递员把货物交给老板,老板负责把货存入库中。但是取货就不对了,用户是自己去检索的。我们在写数据库的时候不关心数据库如何写入,如何管理数据。但是用户在读数据库的时候却要理解数据结构,要自己去磁盘读取数据,删除数据,这不对吧。那如果要完全的实现一个用户不要关心如何读存的数据库。
前台
这里老板就需要一个前台,这个前台负责对接快递员,接到数据后,负责把数据存入库中,也负责构建B+树。这个前台也对接用户,负责把数据从数据库中取出,但是用户要把ID给前台。前台通过检索ID的方式快速取出货物,交给用户。这样就有点数据库的样子了。
分布式
这个时候,为了应对双十一,老板又租了一个货仓。前台负责把数据分到不同的货仓,取的时候也需要根据情况取不同的货仓数据。那么这个时候是不是老板实现了一个分布式数据库?
存算分离
这个时候,双十一来了。前台既要码货,也要给用户取货,忙不过来了,于是老板又请了一个工人,专门负责前台的货物上架,专门负责响应前台要取货物。而前台则专心每个快递进来后应该存哪里,货架编号应该给哪个。那么这个时候是不是老板实现了一个存算分离数据库?
IO瓶颈
IO瓶颈发生在哪里?无非是仓库门不够大(带宽),人跑的不够快(读取速度),一次性读取过多(阻塞其它读取)。通常我们数据库的瓶颈也就发生在这里。但是老板聪明啊,让用户自己拿着ID去找。问题就只有仓库门够不够大了。
失效
- 一天一个用户拿着纸条,上面有货物ID。一般来说,货物ID是这样的1-1-10。但是用户拿着纸条,被他儿子涂鸦过了,只剩下第三部分了。前台接到纸条后头大了,这不就是like ‘%10’,索引失效。全表扫描吧。(和联合索引失效的情况比较像,原理不同)
- 接着用户拿出了第二个纸条,也被他儿子涂鸦过了,但是剩下的是钱两部分。前台接到纸条后,这不就是like ‘1-1%’,万幸,索引还能用一部分。
- 接着用户拿出了第三个纸条,也被他儿子涂鸦过了,但是这次他儿子把第一位-1,第二位+1,第三位*8。前台接到纸条后发现,你这什么啊,我们这都没有0货柜(本质是顺序不存在了)。全表扫描吧。
- 接着用户拿出了第四个纸条,也被他儿子涂鸦过了这次是,他把阿拉伯数字换成了汉字。前台接到纸条后一看,你这数字1是在2前面,但是二是在一前面啊(本质是顺序不存在了)。全表扫描吧。
- 接着用户拿出了第五个纸条,上面有一个他的名字。前台接到纸条后一看。全表扫描吧。
- 接着用户拿出了第六个纸条,上面有一个快递号。前台接到纸条后一看,嘿嘿,我这还有一个索引(非主键索引),掏出笔记本,找到了快递单号对应的货架号,然后去货架上取来了快递。这叫回表。
- 接着用户拿出了第七个纸条,上面有2000个快递号。前台接到纸条后一看,这不就是in()吗?,我库里有2500个快递,还查个屁啊。全表扫描吧。
- 接着用户拿出了第八个纸条,上面既有一个他的手机号,也有一个快递号。前台接到纸条后一看,哎两个索引我都有,但是我不干两次回表事,来回跑太累,手机号索引的第一个就是他这个号码,快递号索引我都翻了两页了还没有,就调手机号吧。(前台选错了索引)
- 用户说,你别急,你看这是什么FORCE INDEX (快递号),这个比较快。
总结
菜鸟驿站的运作模式和数据库的运作模式非常像,硬去寻找对应的话。当然由于两者本质还是有很多不同的,比如缓存啊,事物啊,比如驿站读取就意味着数据删除。这些的不同,本质是来源于底层要处理的事物,要使用的工具,不同导致的。但是,也是可以从某些角度,协助我们理解数据库中一些现象发生的原理的。