数据库自增主键可能的问题

欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

单表的情况下数据库自增id并没有什么问题,在一张表分布到多个数据库的情况下,使用表自增将会出现id重复的问题。
解决的办法有两个方向,一个是在应用层做处理,一个是数据库上去做处理。

目前生成主键方法主要有以下几种:

1、采用mysql自增长主键策略
优点:简单,不需要程序特别处理
缺点:这种方法对以后如果项目移植到其它数据库上改动会比较大,oracle、 db2采用Sequence,mysql、sqlServer又采用自增长,通用性不好

2、使用时间戳+随机数
优点:实现简单,与数据库无关,移植性较好
缺点:长度太长,最少也得20位,不仅占空间并且建索引的话性能会比较差点吧

3、每次取主键最大值+1做为新的主键
优点 :主键长度可控,移植性较好
缺点:并发写可能会造成主键冲突,对并发也不太好控制

4、单独建一个存放主键的表
优点:实现简单,移植性较好
缺点:需要考虑并发问题,整个系统主键生成都依赖该表,性能影响可能较大

即要做到移植性好,性能好,又不会出现并发问题,似乎是没有完美的方案了吗?

一、对于MySQL来说,使用自增还是比较划算的,因为索引使用的底层数据结构(B+树)的原因,如果是自增ID的话,那么数据插入时最多就是引起节点的分裂,而如果是使用非自增ID,则有可能会导致节点移动和分裂。

二、如果使用MySQL又使用UUID作为主键的话,那么插入效率必然大幅下降。
1、当然,使用自增也会带来问题,就是日后如果要做水平切分的话,那么有可能会产生冲突的主键。
2、 而且并发插入的量比较大的时候,MySQL 中如果有自增字段的话,MySQL 会维护一个自增锁,InnoDB 表引擎会在内存里保存一个计数器来记录 AUTO_INCREMENT 值。当插入一个新行数据时,就会用一个表锁来锁住这个计数器,直到插入结束。如果是一行一行的插入是没有问题的,但是在高并发情况下,表锁会引起 SQL 阻塞,极大的影响性能,还可能会达到 max_connections 值。
所以也可以选择不使用数据库的自增,而是自己生成全局唯一的递增整数作为主键。

我们可以自己写一套逻辑, 比如加一些前后缀什么的, 优点就是定制化强而且可以限制长度,缺点就是需要能写出完全随机且支持高并发的程序, 那肯定就有用到pool的一些机制, 以及如何down机的持久化问题, 一般人写不出。
一般点儿的比如我就是就直接用java的uuid方法去生成, 优点就是简单,很轻松的就支持了分库分表, 缺点当然就是长度太长, 占空间大, 且无规律(如果你想要规律的话).
主键和订单号是不一样的, 主键是与业务无关, 而订单号是与业务相关的, 所以不可能完全避免不去写这种生成唯一id的程序, 虽然很难, 订单号可以与时间戳相关加一些随机的后缀(uuid随机截取4位)来实现。

最终方案:

根据自己项目实际情况来定!!!没有一套规定的方案适合任何一个系统。

1、项目基础功能部分,例如菜单功能管理、用户管理、权限管理、机构组织管理、参数管理等采用【方案3】,这些功能一般数据量不大,基本没有大的性能问题和并发问题,如果移植的话改动也比较小 。

2、对于某些流水、日志类的表可采用【方案2】时间戳+随机数,自己写一套生成唯一id的程序,可以采用时间戳+uuid截取最后四位来作为唯一id,时间戳做主键此时会更有意义 。

3、对于系统中大部分实际的业务功能采用【方案1】mysql的自增长策略,这样可减少开发工作量,并且性能和并发都有保障,如果项目就算移植的话,业务功能这部分肯定会有些变动,做二次开发,所以就暂不考虑移植性了。

4、对于分库分表的场景,可以采用雪花算法。针对分库分表的场景其他几种解决方案参照:分布式集群下如何做到唯一序列号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老周聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值