淘宝的数据库,主键是如何设计的?
破产码农
1
自增ID的问题
2
淘宝的主键设计
1550672064762308113
1481195847180308113
1431156171142308113
1431146631521308113
3
主键的设计
为什么UUID是全局唯一的?
为什么UUID占用36个字节?
为什么UUID是无序的?
UUID = 时间低(8字节)- 时间中高+版本(8字节)- 时钟序列 - MAC地
为了更为详细的讲解UUID的实现,我们以UUID值e0ea12d4-6473-11eb-943c-00155dbaa39d举例,其具体组成如下图所示:
在UUID中他的时间部分占用60位,存储的类似TIMESTAMP的时间戳,但表示的是从1582-10-15 00:00:00.00到现在的100ns的计数。
可以看到UUID存储的时间精度比TIMESTAMPE更高,时间维度发生重复的概率降低到1/100ns。
时钟序列是为了避免时钟被回拨导致产生时间重复的可能性。MAC地址用于全局唯一。这回答了为什么UUID可以是全局唯一的问题。
UUID根据字符串进行存储,设计时还带有无用"-"字符串,因此总共需要36个字节。
最后,为什么UUID是随机无序的呢?
因为UUID的设计中,将时间低位放在最前面,而这部分的数据是一直在变化的,并且是无序!!!
若将时间高低位互换,则时间就是单调递增的了,也就变得单调递增了。
MySQL 8.0解决了UUID存在的问题,除去了UUID字符串中无意义的"-"字符串,并且将字符串用二进制类型保存,这样存储空间降低为了16字节。
更重要的是,他可以更换时间低位和时间高位的存储方式,这样UUID就是有序的UUID了。
可以通过MySQL8.0提供的uuid_to_bin函数实现上述功能,同样的,MySQL也提供了bin_to_uuid函数进行转化:
所以,现在起可以通过函数uuid_to_bin(@uuid,true)将UUID转化为有序UUID了。
全局唯一 + 单调递增,这不就是我们想要的主键实现么?
BTW,8.0之前的版本没有提供这两个函数,有聪明的小伙伴知道怎么实现么?欢迎留言。
4
有序UUID性能测试
16字节的有序UUID,相比之前8字节的自增ID,性能和存储空间对比究竟如何呢?
我们来做一个测试,插入1亿条数据,每条数据占用500字节,含有3个二级索引,最终的结果如下所示:
从上图可以看到插入1亿条数据有序UUID是最快的,而且在实际业务使用中有序UUID在业务端就可以生成。还可以进一步减少SQL的交互次数。
另外,虽然有序UUID的相比自增ID多了8个字节,但实际只增大了3G的存储空间。
存储空间的增大并没有小伙伴想象中的那么大。
5
总结
在当今的互联网环境中,非常不推荐自增ID作为主键的数据库设计。
更推荐类似有序UUID的全局唯一的实现。
另外在真实的业务系统中,主键还可以加入业务和系统属性,如用户的尾号,机房的信息等。
这样的主键设计就更为考验架构师的水平了。
今天所介绍的全部内容都发布在拉钩教育推出的专栏《姜承尧的MySQL实战宝典》中,欢迎大家订阅。
更重要的是,每周五晚21:30分,我将在抖音直播对于《姜承尧的MySQL实战宝典》相关问题的答疑。抖音号:破产码农
直播预告
往期推荐
注意了!这个远古Bug,让你的 MySQL 8.0 性能下降2倍!
MySQL vs Redis,新时代王者的较量
刚刚,MySQL 战胜了老大哥 Memcached!
震惊!MySQL 8.0 220W QPS轻松达成
MySQL 8.0使用三周后,我再也看不上5.7版本了