专栏首页洁癖是一只狗自增id用完怎么办

自增id用完怎么办

我们知道mysql中存在很多自增id,然后不断增长,由于只要给id定义了这个数的字节长度,那么他就有了上限,比如无符号整型(unsigned int)是4个字节,因此他的上限是2^32-1,

表定义自增值id

表定义的自增值达到上限后的逻辑是,在申请下一个id时,得到的值保持不变.

因此当我们达到上限的时候(id=4294967295),就会导致下一个insert语句拿到相同的id,试图执行的时候,就会报主键冲突错误,因此在建表的时候你需要你的表是否可能达到这个上限,如果有可能就应该创建8个字节的bigint unsigned

InnoDB系统自增row_id

如果你创建的InnoDB表没有指定主键,那么InnoDB会给你创建一个不可见的,长度为6字节的row_id,InnoD维护了一个dict_sys.row_id,所有无主键的InnoDB表,每插入一行数据,就会把这个值赋值给row_id,然后把dict_sys_row_id的值加1.

此时的row_id写到数据库的值有两个特征

  1. row_id写入表的范围是0-2^48-1
  2. 当dict_sys.row_id=2^48时候,在插入数据申请的row_id,就会变为0

也就是说写入表的row_id是从0开始到2^48-1,达到上限后,下一个值就是0,然后继续循环,虽然2^48-1本身就很大,但是他还是有上限的,且在innoDB逻辑里,申请row_id=N后,就将这行写入表中,如果表中已经存在row_id=N,就覆盖以前的行

由于有可能覆盖数据,意味着数据丢失,影响的是数据可靠性。而报主键冲突影响的是可用性,一般情况下,可靠性高于可用行

XID

xid是记录对应事务用的,xid是如何生成的呢?

其实在mysql内部维护了一个全局变量global_query_id,每次执行语句的时候将他赋值给Query_id,然后给这个变量加1,如果当前语句是这个事务的第一条语句,就会把Query_id赋值给xid,

而global_query_id在数据库重启之后,就会清零,所以同一个数据库实例中,不同事务的xid也是有可能相同,但是mysql重启之后也会重新生成binlog,因此binlog日志里面的xid是唯一的,但是如果global_query_id达到上限之后,就会继续从0开始计算,理论上还是会出现同一个binlog有相同的xid,又因为global_querey_id定义为8个字节,自增的上限是2^64-1,所以出现的概率很小,仅存在理论上

Innodb trx_id

首先要知道的是xid是有server层维护的,InnoDB内部使用Xid,就是为了能够在InnoDB事务和server之间做关联,但是innoDB自己trx_id,是另外维护的

innoDB内部维护了一个max_trx_id全局变量,每次申请一个姓的trx_id,就会获取max_trx_id的当前值,然后并将max_trx_id加1.

InnoDB数据可见性核心思想是,每一行数据都记录了更新他的trx_id,当一个事物读到一行数据的时候,判断这个数据是否可见的方法,就是通过事物的一致性视图与这行数据的trx_id做对比。

我们可以从information_schema.innodb_trx表中看到事物trx_id,如下图

我们发现T2时刻的trx_id的值很大,而T4时刻是一个正常的值,这个是为什么呢

在T1时刻sessionA没有涉及更新操作,是一个只读事物,而只读事务InnoDB是不会分配trx_id,但是我们还会发现一个问题,就是在执行uodate和delete执行之后,事物的trx_id不止加1,那是因为update和delete除了事物本身,还涉及到标记深处旧数据,也就是把数据导到purge队列里等到后续物理删除,这个操作也会max_trx_id+1,因此一个事物中至少加2,还有就是innoDB的后台操作,比如表达索引信息统计这个类也是会启动内部事务的因此可以看到,trx_id值并不是按照加1递增的

现在我们看看为什么T2的trx_id的为什么那么大,他的算法是把当前事务trx变量的指针地址转成整数,再加上2^48,使用这个算法,可以保证下面两点

  1. 因为同一个只读事务在执行期间,他的指针地址是不会变的,所以不论是在innodb_trx还是在innodb_locks表里,同一个只读事务查出来trx_id就会是一样的
  2. 如果并行的多个只读事务,每个事务trx变量的执行地址肯定不同,这样不同的并发只读事务,查出来的trx_id就是不同的

我们这个算法为什么要加2^48

目的就是保证只读事务显示trx_id值比较大,这个只是为了在正常情况下,区别读写事务的id,但是trx_id跟row_id的逻辑类似,定义为8个字节,因此理论上可能会出现一个读写事务和只读事务显示的trx_id相同的情况,不过概率很低

为什么只读事务不分配trx_id,有什么好处呢

  1. 这样可以较少事务视图里面活跃事务数组的大小,因为当前正在运行的只读事务,是不影响数据的可见性判断的,所以在创建事务的一致性视图的时候,InnoDB只需要拷贝读写事务的trx_id
  2. 可以减少trx_id的申请,在InnoDB即使你只执行一个普通的select语句,在执行过程中,也对应一个只读事务,所以只读事务优化后,普通的查询语句不需要申请trx_id,就大大减少了并发申请事务trx_id的所冲突

最后我们要知道max_trx_id会持久化存储,重启也不会重置为0,理论上,只要mysql运行的时间够长,就会可能达到上限,然后从0开始的情况

因此他会出现一个脏读的bug,如下图

在T2时刻sessionB执行第一条update语句的事物id就是2^48-1,而第二条语句update,语句的事务id就是0了,

在T3时刻sessionA执行select语句的时候,判断可见性发现C=3这个数据版本的trx_id,小于事物TA的低水位,因此这个数据就是可见的,这个就是脏读的bug,由于低水位会只需增加,而事务id从0开始计数,不管是否重启数据库,这个bug任然存在。

thread_id

线程id是我们最常见的一种自增id,我使用show processlist的第一列计数就是thread_id,

thread_id的逻辑很好理解,系统保存一个全局变量thread_id_conuter,每新建一个连接,就将thread_id_counter赋值个这个新连接的线程变量,他的上限是2^32-1.当达到上限之后,就会重置为0,然后持续增加,但是并不会出现show processlist看到相同的thread_id,是因为mysql设计了一个唯一数组的逻辑,给新线程分配thread_id的收逻辑代码如下,因此不会出现相同的thread_id

do {
  new_id= thread_id_counter++;
} while (!thread_ids.insert_unique(new_id).second);

如果对您有一丝丝帮助,麻烦点个关注,也欢迎转发,谢谢

本文分享自微信公众号 - 洁癖是一只狗(rookie-dog),作者:洁癖汪

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-02-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自增id用完了怎么办

    如果创建的表使用InnoDB引擎,但是没有指定主键的话。InnoDB会创建一个不可见,长度为6个字节的row_id。

    用户7447819
  • 面试官问:MySQL 的自增 ID 用完了,怎么办?

    公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。

    java进阶架构师
  • 面试官问:MySQL的自增ID用完了,怎么办?

    可以发现 AUTO_INCREMENT 已经自动变成2,这离用完还有很远,我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 intunsigned...

    xcbeyond
  • 面试官问:MySQL的自增ID用完了,怎么办?

    可以发现 AUTO_INCREMENT 已经自动变成2,这离用完还有很远,我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 intunsigned...

    田维常
  • 面试官问:MySQL的自增 ID 用完了,怎么办?

    如果你用过或了解过MySQL,那你一定知道自增主键了。每个自增id都是定义了初始值,然后按照指定步长增长(默认步长是1)。虽然,自然数是没有上限的,但是我们在设...

    搜云库技术团队
  • [MySQL] 数据库自增ID用完了会怎么样

    1.有主键 如果设置了主键,并且一般会把主键设置成自增。 我们知道,Mysql里int类型是4个字节,如果有符号位的话就是[-2^31,2^31-1],无符号位...

    陶士涵
  • 面试官:数据库自增ID用完了会怎么样?

    看到这个问题,我想起当初玩魔兽世界的时候,25H难度的脑残吼的血量已经超过了21亿,所以那时候副本的BOSS都设计成了转阶段、回血的模式,因为魔兽的血量是int...

    艾小仙
  • 面试官:MySQL中的自增主键用完了怎么办?

    这个问题是一个粉丝给我提的,我觉得挺有意(KENG)思(B)! 于是,今天我们就来谈一谈,这个自增主键用完了该怎么办!

    帅地
  • MySQL 主键 自增 ID 会用完吗?

    首先我们一般创建 MySQL 数据表的时候,大部分情况下会创建一个自增主键ID 的字段,可能你的建表语句如下:

    hedeqiang
  • 自增主键用完了该咋办?

    这个问题是一个粉丝给我提的,我觉得挺有意(KENG)思(B)! 于是,今天我们就来谈一谈,这个自增主键用完了该怎么办!

    zhisheng
  • Mybatis【6】-- Mybatis插入数据后自增id怎么获取?

    我们知道很多时候我们有一个需求,我们需要把插入数据后的id返回来,以便我们下一次操作。

    秦怀杂货店
  • Redis:内存被我用完了!该怎么办?

    Redis是一个内存数据库,当Redis使用的内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,交换会导致Redis性能急剧下降。所以在生产环境中我们通...

    Java识堂
  • 面试官:数据库自增 ID 用完了会咋样?

    哈喽,好久没更新啦。因为最近在面试。用了两周时间准备,在 3 天之内拿了 5 个 offer,最后选择了广州某互联网行业独角兽 offer,昨天刚入职。这几天刚...

    一个优秀的废人
  • 无法在此iPhone激活面容ID怎么办?

    最近许多苹果用户在论坛反馈无法激活面容ID。在这篇文章中,我们将探讨可能导致该问题的原因以及解决办法。

    莉莉的碎碎念
  • iPhone手机总是弹出输入ID密码怎么办?

    更新到最新的iOS 15版本后,您的iPhone可能一直弹出ID,要求输入密码。别担心!在本文中,我将向您介绍当您的iPhone总是提示要输入Apple ID密...

    莉莉的碎碎念
  • iPhone被陌生人的Apple ID锁机了怎么办呢?

    最近收到一封用户邮件,邮件的内容显示用户想免费下载一付费app就从某宝购买了其他人的Apple ID信息。登陆之后确实是可以免费下载了,但突然显示iPhone已...

    洋葱雪饼
  • ai源文件导入ID后显示模糊该怎么办?

    我们在将AI的源文件拖入ID的画布上时往往是会发现像素比较低,比较不清晰,这是因为软件默认低能耗防止软件卡顿,不过我们可以手动调节到高清,具体该怎么操作呢?下面...

    砸漏
  • Nginx 挂了怎么办?怎么实现高可用?

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

    杰哥的IT之旅
  • 面试被问分布式ID怎么办? 滴滴(Tinyid)甩给他

    Tinyid是滴滴开发的一款分布式ID系统,Tinyid是在美团(Leaf)的leaf-segment算法基础上升级而来,不仅支持了数据库多主节点模式,还提供了...

    程序员内点事

扫码关注云+社区

领取腾讯云代金券