展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

主键设计

  • 自增ID的问题
可靠性不高
存在自增ID回溯的问题,这个问题直到最新版本的MySQL8.0才修复。

安全性不高
对外暴露的接口可以非常容易猜测对应的信息。比如:/User/1/这样的接口,可以非常容易猜测用户ID的值为多少,总用户数量有多少,也可以非常容易地通过接口进行数据的爬取。

性能差
自增ID的性能较差,需要在数据库服务器端生成。

交互多
业务还需要额外执行一次类似last_insert_id()的函数才能知道刚才插入的自增值,这需要多一次的网络交互。在海量并发的系统中,多1条SQL,就多一次性能上的开销。

局部唯一性
最重要的一点,自增ID是局部唯一,只在当前数据库实例中唯一,而不是全局唯一,在任意服务器间都是唯一的。对于目前分布式系统来说,这简直就是噩梦。
  • 淘宝的主键设计
订单ID + 时间 + 去重字段 + 用户ID后6位尾数
  • 推荐的主键设计
非核心业务:对应表的主键自增ID,如告警、日志、监控等信息。

核心业务:主键设计至少应该是全局唯一且是单调递增。全局唯一保证在各系统之间都是唯一的,单调递增是希望插入时不影响数据库性能。
  • uuid
全局唯一,占用36字节,数据无序,插入性能差。

UUID = UUID=时间+UUID版本(16字节)-时钟序列(4字节)-MAC地址(12字节)

  • UUID如何做到全局唯一
在UUID中时间部分占用60位,存储的类似TIMESTAMP的时间戳,但表示的是从1582-10-15 00:00:00.00到现在的100ns的计数。可以看到UUID存储的时间精度比TIMESTAMPE更高,
时间维度发生重复的概率降低到1/100ns。

时钟序列是为了避免时钟被回拨导致产生时间重复的可能性。MAC地址用于全局唯一。
  • UUID占用36个字节
UUID根据字符串进行存储,设计时还带有无用”-”字符串,因此总共需要36个字节
  • UUID改造
若将时间高低位互换,则时间就是单调递增的了,也就变得单调递增了。MySQL8.0可以更换时间低位和时间高位的存储方式,这样UUID就是有序的UUID了。

MySQL8.0还解决了UUID存在的空间占用的问题,除去了UUID字符串中无意义的"-"字符串,并且将字符串用二进制类型保存,这样存储空间降低为了16字节。

可以通过MysQL8.0提供的uuid_to_bin函数实现上述功能,同样的,MysQL也提供了bin_to_uuid函数进行转化:

SET @uuid = UUID();

SELECT @uuid,uuid_to_bin(@uuid),uuid_to_bin(@uuid,TRUE);

uuid_to_bin(@uuid,TRUE)就可作为主键使用
```
posted @ 2022-06-17 16:45  DogLeftover  阅读(19)  评论(0编辑  收藏  举报