自增还是UUID?MYSQL数据库主键的类型选择

自增还是UUID?这个问题看似简单,但是能诱发很多思考,也涉及到了很多细节。网上的确有很多有关这方面的资料,但是比较乱,今天我结合这些资料和自己的心得,单独对这个话题写一篇博客出来,希望对大家有所帮助哈。

先说下uuid和 auto_increment(数据库自增主键)的优缺点吧,因为是个人理解,如有错误恳请指出:

auto_incremen的优点:

  1. 字段长度较uuid小很多,可以是bigint甚至是int类型,这对检索的性能会有所影响。我们平时数据库一般用的都是innodb引擎的表,这种表格检索数据的时候,哪怕走索引,也是先根据索引找到主键,然后由主键找到这条记录。所以主键的长度短的话,读性能是会好一点的。
  2. 在写的方面,因为是自增的,所以主键是趋势自增的,也就是说新增的数据永远在后面,这点对于性能有很大的提升(这点我接下来会在uuid的优缺点分析中解释,虽然用词可能不太专业)。

auto_incremen的缺点:

  1. 最致命的一个缺点就是,很容易被别人知晓业务量,然后很容易被网络爬虫教做人
  2. 高并发的情况下,竞争自增锁会降低数据库的吞吐能力
  3. 数据迁移的时候,特别是发生表格合并这种操作的时候,会非常蛋疼

接下来说下uuid的优点:

  1. 地球唯一的guid,绝对不会冲突
  2. 可以在应用层生成,提高数据库吞吐能力
  3. 是string类型,写代码的时候方便很多

uuid的缺点

  1. 与自增相比,最大的缺陷就是随机io。这一点又要谈到我们的innodb了,因为这个默认引擎,表中数据是按照主键顺序存放的。也就是说,如果发生了随机io,那么就会频繁地移动磁盘块。当数据量大的时候,写的短板将非常明显。当然,这个缺点可以通过nosql那些产品解决。
  2. 读取出来的数据也是没有规律的,通常需要order by,其实也很消耗数据库资源
  3. 看起来比较丑

这样子一看,似乎两种主键方案都有其致命的缺点,那怎么搞呢?比如遇到必须用mysql但是量比较大,并发比较高的情况?其实行业内大鳄已经给出了一个比较好的解决方案,那就是推特的雪花算法(snowflake):

这里写图片描述
雪花算法简单描述:
+ 最高位是符号位,始终为0,不可用。
+ 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
+ 10位的机器标识,10位的长度最多支持部署1024个节点。
+ 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。

看的出来,这个算法很简洁也很简单,但依旧是一个很好的ID生成策略。最高的那几位是时间戳,这能保证不管是几台机子在跑主键的生成必然是趋势自增的,基本上下一毫秒产生的主键必然比上一毫秒的大。最后的几位是加锁的方法生成的,一台机器一毫秒钟4096个,够用了吧?唯一的难点是机器号的生成。我想了想,大概有几个方法:

  1. 根据机器的mac地址等信息生成,简单点的话,就根据机器的ip生成(这样子做是有风险的,哪怕保证买来的机器都是连号的,根据ip计算一样可能导致算出同样的机器id)
  2. 用zookeeper给机器发号,这是最稳妥的,真要用雪花算法生成线上数据的id,我觉得还是得靠这个方案
  3. 用其他中间组件生成,比如redis自增等原子性操作获取机器编号。

zk那些我不是很会,我就拿第三种方案,结合spring data jpa写个小demo:

这里写图片描述

然后是主键生成器的实现类,需要实现接口:

这里写图片描述

这里写图片描述

当然判断的逻辑可以再写详细点。
这里要注意的是,redis的加载必须要在db之前完成,所以redis和db的配置文件需要改变下:
这里写图片描述

这里写图片描述

这种方案比较简单,但是的确也存在一个危险周期(如果这个机器编号是取模生成的),而且万一redis数据被清空了,可能机器编号也会重复…网上关于这方面的资料比较少,除了zk发号(其实我也不会),我也想不到有更好的办法,如果大家有更好的方案,可以随时留言或者找我…

我这边有新的好的想法也会随时更新这篇博客~

  • 4
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值