首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >mysql的rowid使用完了会怎样?

mysql的rowid使用完了会怎样?

原创
作者头像
大大刺猬
发布2026-06-29 17:25:18
发布2026-06-29 17:25:18
1200
举报
文章被收录于专栏:大大刺猬大大刺猬

6月快结束了, 赶紧水一篇

导读

创建表的时候, 我们强烈建议要设置主键/唯一索引, 没得合适的字段,就加个自增字段也行.

我们知道, 如果建表时,未指定主键,则mysql会自动添加一个自增的隐藏字段rowid来作为主键. 该rowid全局共用(dict_sys->row_id),使用6字节(存储)表示,也就是能表示281474976710656(281万亿)个值,不太可能达到上限,毕竟mac地址也是6字节(48bit).

但是,既然有上限,且全局共用, 就总是有使用完的情况的, 那么使用完了会怎么样?

模拟rowid使用完

rowid是无法使用sql查询出来的, 怎么观察呢?

我们之前写的ibd2sql-v1.x版本有debug模式, 是能看到所有隐藏字段的:rowid,trxid,rollptr.

代码语言:shell
复制
python3 main.py /data/mysql_5744/mysqldata/db1/t20260629_01.ibd --debug --sql | grep -E 'data:|ROW_ID:'

怎么模拟使用完呢? 总不能insert 281万亿行数据吧... 既然是全局的,那么通常就有相关的'全局变量': dict_sys->row_id

也就是可以使用如下命令查看和修改

代码语言:shell
复制
# 查看
gdb -p `pidof mysqld` --batch --ex 'print dict_sys->row_id'

# 修改
gdb -p `pidof mysqld` --batch --ex 'set dict_sys->row_id=1'

准备测试表

先初始化rowid为1,方便后续验证

准备测试数据:

代码语言:sql
复制
create table db1.t1(c1 int);
create table db1.t2(c2 int);
insert into db1.t1 values(1),(2);
insert into db1.t2 values(1),(2);
insert into db1.t1 values(3);

观察此时的rowid分布情况

代码语言:txt
复制
17:03:55 [root@ddcw21 ibd2sql-ibd2sql-v1.x]#python3 main.py /data/mysql_5744/mysqldata/db1/t1.ibd --debug --sql | grep -E 'data:|ROW_ID:'
[2026-06-29 17:03:57] [DEBUG] 	 ROW_ID:1
[2026-06-29 17:03:57] [DEBUG] 	145 ----> 149 data:1  bdata:b'\x80\x00\x00\x01'
[2026-06-29 17:03:57] [DEBUG] 	 ROW_ID:2
[2026-06-29 17:03:57] [DEBUG] 	174 ----> 178 data:2  bdata:b'\x80\x00\x00\x02'
[2026-06-29 17:03:57] [DEBUG] 	 ROW_ID:5
[2026-06-29 17:03:57] [DEBUG] 	203 ----> 207 data:3  bdata:b'\x80\x00\x00\x03'
17:03:57 [root@ddcw21 ibd2sql-ibd2sql-v1.x]#
17:03:59 [root@ddcw21 ibd2sql-ibd2sql-v1.x]#python3 main.py /data/mysql_5744/mysqldata/db1/t2.ibd --debug --sql | grep -E 'data:|ROW_ID:'
[2026-06-29 17:04:04] [DEBUG] 	 ROW_ID:3
[2026-06-29 17:04:04] [DEBUG] 	145 ----> 149 data:1  bdata:b'\x80\x00\x00\x01'
[2026-06-29 17:04:04] [DEBUG] 	 ROW_ID:4
[2026-06-29 17:04:04] [DEBUG] 	174 ----> 178 data:2  bdata:b'\x80\x00\x00\x02'

我们发现: t1.c1=1时,rowid为1; t1.c1=2时,rowid为2; t2.c2=1时,rowid=3,t2.c2=2时,rowid=5;t1.c1=3时,rowid为5.

即rowid确实是全局共用且自增的.

使用gdb设置rowid的全局值达到上限

然后我们使用gdb来设置下rowid的值为: 281474976710654

代码语言:shell
复制
gdb -p `pidof mysqld` --batch --ex 'set dict_sys->row_id=281474976710654'

然后我们再往t1表插入4条数据看下:

代码语言:sql
复制
insert into db1.t1 values(4);
insert into db1.t1 values(5);
insert into db1.t1 values(6);
insert into db1.t1 values(7);
select * from db1.t1;

我们发现少了条数据:1

然后我们使用ibd2ql来看下

我们看到:c1为5时,row_id达到了上限281474976710655, 当c1=6时,row_id变成了0, 当c1=7时,row_id变成了1,并把之前的c1=1覆盖了.

我们再看下dict_sys->row_id的值呢?

发现dict_sys->row_id为281474976710658, 已经超过了6字节,也没有溢出. 查看源码发现row_id的类型是ib_uint64_t, 即该变量使用8字节表示, 但page中只使用后6字节.....

总结

mysql的row_id是全表共用的, 即对所有表都唯一. 当rowid达到上限(6字节)后,会从0开始,并覆盖原来的数据(无告警,无报错, 就单纯的丢掉数据).

row_id在数据字典(dict_sys_t)使用8字节表示, 但在page中只使用6字节. 问题来了,当row_id在内存中到8字节上限又会怎么样呢?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 模拟rowid使用完
    • 准备测试表
    • 使用gdb设置rowid的全局值达到上限
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档