千家信息网

怎么理解MYSQL的auto_increment_offset和auto_increment_increment值

发表于:2025-02-05 作者:千家信息网编辑
千家信息网最后更新 2025年02月05日,本篇内容主要讲解"怎么理解MYSQL的auto_increment_offset和auto_increment_increment值",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下
千家信息网最后更新 2025年02月05日怎么理解MYSQL的auto_increment_offset和auto_increment_increment值

本篇内容主要讲解"怎么理解MYSQL的auto_increment_offset和auto_increment_increment值",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么理解MYSQL的auto_increment_offset和auto_increment_increment值"吧!

实际上两个值是这样的:
我们理解auto_increment_offset为0开始的偏移量
auto_increment_increment是一个步长
auto_increment_offset+(N-1)*auto_increment_increment
N代表的是插入的次数。这算出来实际上是在0-+∽ 之间可以设置的值。
打个比方
mysql> set auto_increment_offset=2;
Query OK, 0 rows affected (0.00 sec)

mysql> set auto_increment_increment=5;
Query OK, 0 rows affected (0.00 sec)

这样我们允许的值是2 7 12 17 ....
我们建立一个表

mysql> create table testcr11(id int primary key auto_increment) AUTO_INCREMENT=1;
Query OK, 0 rows affected (0.22 sec)
mysql> insert into testcr11 values(NULL);
Query OK, 1 row affected (0.01 sec)
mysql> select * from testcr11;
+----+
| id |
+----+
| 2 |
+----+
1 row in set (0.00 sec)

可以看到值并不是1开始而是2,在插入一行

mysql> insert into testcr11 values(NULL);
Query OK, 1 row affected (0.20 sec)
mysql> select * from testcr11;
+----+
| id |
+----+
| 2 |
| 7 |
+----+
2 rows in set (0.00 sec)
可以看到没有问题

但是问题是遇到如下一个提示:
When the value of auto_increment_offset is greater than that of
auto_increment_increment, the value of auto_increment_offset is ignored

也就是如果auto_increment_offset>auto_increment_increment ,auto_increment_offset将被忽略。
这个也可以理解,比如
auto_increment_offset = 10
auto_increment_increment = 5

按照公式我们第一次插入的值是10 15 20 ,但是我们发现在0-+∽这样一个线性范围内,我们丢掉了一个
这个值就是10-5 = 5,如果我们这样理解就理解得通了,但是事实真是这样吗?
我打开源码:
看到如下的计算方式
inline ulonglong
compute_next_insert_id(ulonglong nr,struct system_variables *variables)
{
const ulonglong save_nr= nr;
if (variables->auto_increment_increment == 1)
nr= nr + 1; // optimization of the formula below
else
{
nr= (((nr+ variables->auto_increment_increment -
variables->auto_increment_offset)) /
(ulonglong) variables->auto_increment_increment);
nr= (nr* (ulonglong) variables->auto_increment_increment +
variables->auto_increment_offset);
}

if (unlikely(nr <= save_nr))
return ULLONG_MAX;
return nr;
}


我使用了GDB进行断点调试如下:
(gdb) p nr
$1 = 0
(gdb) n
3479 if (variables->auto_increment_increment == 1)
(gdb) p save_nr
$2 = 0
(gdb) p variables->auto_increment_increment
$3 = 5
(gdb) p variables->auto_increment_offset
$4 = 10
(gdb) n
3485 (ulonglong) variables->auto_increment_increment);
(gdb) p nr
$5 = 0
(gdb) n
3487 variables->auto_increment_offset);
(gdb) p nr
$6 = 3689348814741910322
(gdb) n
3490 if (unlikely(nr <= save_nr))
(gdb) p save_nr
$7 = 0
(gdb) p nr
$8 = 4
(gdb) n
3493 return nr;

这样我们找到了问题所在
(gdb) p nr
$6 = 3689348814741910322

这里
(((nr+ variables->auto_increment_increment -
variables->auto_increment_offset)) /
(ulonglong) variables->auto_increment_increment);
variables->auto_increment_increment -
variables->auto_increment_offset
这里出现了负数,但是运算的时候是无符号longlong类型,自动类型转换后得到
了一个非常大的
$6 = 3689348814741910322
这里出现了异常最后得到了一个数字 4
然后我们插入的就是4
mysql> select * from testcr5;
+----+
| id |
+----+
| 4 |
+----+
1 row in set (0.00 sec)

也许如果auto_increment_offset>auto_increment_increment会由于转换问题得到一个
不确定的结果干脆叫做
When the value of auto_increment_offset is greater than that of
auto_increment_increment, the value of auto_increment_offset is ignored
------------------------------------------------------------------------------------------------------------------
下面是具体计算过程:
如果我们要刨根问题为什么是4这个问题需要涉及到很多东西我们先来看变量的类型

先给出计算源码
typedef unsigned long long ulonglong;
typedef unsigned long ulong;

nr= (((nr+ variables->auto_increment_increment -
variables->auto_increment_offset)) /
(ulonglong) variables->auto_increment_increment);

nr= (nr* (ulonglong) variables->auto_increment_increment +
variables->auto_increment_offset);

给出类型

nr (ulonglong *) =0(初始)
variables->auto_increment_increment (ulong *) =5
variables->auto_increment_offset (ulong *) =10

在64位LINUX上ULONG 和ULONGLONG都是8字节,所以我们认为他们表示的范围相同,他们则相同
同时我们还需要知道ulonglong是不能存储负数的
而variables->auto_increment_increment - variables->auto_increment_offset =-5 他转换为
ulong正数就是 18446744073709551611 为什么是这么多呢?
首先我们要看5的ulong的表示如下:
0 0000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101 最开始的是符号位
反码
0 1111111 11111111 11111111 11111111 11111111 11111111 1111111111111010
补码
0 1111111 11111111 11111111 11111111 11111111 11111111 11111111 11111011
我们都没有动符号位,实际上负数的符号位是1所以是
1 1111111 11111111 11111111 11111111 11111111 11111111 11111111 11111011
好下面我们看看他的16进制表示
FF FF FF FF FF FF FF FB 这就是-5long的表示,因为ULONG没有负数那么将符号位作为数字表示位
那么转换为10进制实际上就是
18446744073709551611
下面是我GDB 出来的,因为小端Little_endian是不管在内存和磁盘中存储都是内存的低地址存储数值的低位数
实际上0xfb 0xff 0xff 0xff 0xff 0xff 0xff 0xff
fb是低位
( http://blog.itpub.net/7728585/viewspace-2124159/ 关于大端小端)
(gdb) p test
$1 = 18446744073709551611
(gdb) p &test
$2 = (ulonglong *) 0x7fffffffea28
(gdb) x/8bx 0x7fffffffea28
0x7fffffffea28: 0xfb 0xff 0xff 0xff 0xff 0xff 0xff 0xff
既然
nr+ variables->auto_increment_increment = 18446744073709551611
我们来看下一步
/(ulonglong) variables->auto_increment_increment
实际上就是
18446744073709551611 / 5 = 3689348814741910322
为什么是3689348814741910322 明显丢掉了一个1
实际上
3689348814741910322*5 = 18446744073709551610
因为整数是不能表示浮点数的,在C语言中使用丢弃小数点后的值。这里就丢了1,这其实就是为什么是4 而不是 5的原因
那么(初始的nr=0)
nr= (((nr+ variables->auto_increment_increment -
variables->auto_increment_offset)) /
(ulonglong) variables->auto_increment_increment);
nr = 3689348814741910322
接下来做的是
nr= (nr* (ulonglong) variables->auto_increment_increment +variables->auto_increment_offset);
nr* (ulonglong) variables->auto_increment_increment 我们已经说了他的值就是
3689348814741910322*5 = 18446744073709551610
然后
18446744073709551610+variables->auto_increment_offset
就是
18446744073709551610+10
我来看一下 18446744073709551610 二进制
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111010
10的二进制
1010 低位相加
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111010
+ 1010
-----------------------------------------------------------------------
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000100
我们明显的看到了溢出。溢出就抛弃掉了剩下就是
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000100
就是十进制的4 。
这就是4计算出来的原因。
所以MYSQL官方文档使用一个忽略来表示,实际上是不确定的值如果
如果
auto_increment_offset 远远大于 variables->auto_increment_increment
比如auto_increment_offset=1000
auto_increment_increment = 2
那么只要
nr+ variables->auto_increment_increment< variables->auto_increment_offset
那么值都是不确定的这里的nr是存储上一次来的自增值,初始为0
nr+ variables->auto_increment_increment - variables->auto_increment_offset
所以基于这个原因,建议大家注意auto_increment_increment 大于 auto_increment_offset
是必要的。

下面是一个简单程序演示这个过程:

点击(此处)折叠或打开

  1. #include


  2. typedef unsigned long long ulonglong;

  3. typedef unsigned long ulong;


  4. int main(void)

  5. {

  6. ulonglong nr = 0;

  7. ulonglong nr1;

  8. ulong auto_increment_increment = 5;

  9. ulong auto_increment_offset = 10;

  10. ulonglong t1=-5;

  11. ulonglong test1;

  12. printf("ulonglong size is:%lu ulong size is:%lu\n",sizeof(unsigned long long),sizeof(unsigned long));

  13. printf("nr init values is:%llu\n",nr);

  14. printf("auto_increment_increment is:%lu\n",auto_increment_increment);

  15. printf("auto_increment_offset is :%lu\n",auto_increment_offset);

  16. nr= (((nr+ auto_increment_increment - auto_increment_offset))/(ulonglong)auto_increment_increment );

  17. printf("-5 ulonglong is :%llu\n",t1);

  18. printf("nr+ auto_increment_increment - auto_increment_offset))/(ulonglong)auto_increment_increment is:%llu\n",nr);

  19. test1 = nr* (ulonglong)auto_increment_increment;

  20. nr= (nr* (ulonglong)auto_increment_increment + auto_increment_offset);

  21. printf("nr* (ulonglong)auto_increment_increment is: %llu\n",test1);

  22. printf("last nr is: %llu\n",nr);


  23. }


跑一下如下:
ulonglong size is:8 ulong size is:8
nr init values is:0
auto_increment_increment is:5
auto_increment_offset is :10
-5 ulonglong is :18446744073709551611
nr+ auto_increment_increment - auto_increment_offset))/(ulonglong)auto_increment_increment is:3689348814741910322
nr* (ulonglong)auto_increment_increment is: 18446744073709551610
last nr is: 4

到此,相信大家对"怎么理解MYSQL的auto_increment_offset和auto_increment_increment值"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

就是 实际 实际上 问题 符号 类型 负数 存储 原因 明显 相同 二进制 低位 内存 内容 数字 源码 范围 过程 进制 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 全天候网络安全态势 南充通信网络安全 怎么开通LOL手游的服务器 北京软件开发招工 沂慧网络技术有限公司 乡镇举行网络安全活动的简报 任意门网络安全手抄报 我的世界神奇宝贝服务器版权 开源数据库有哪些 沈师数据库原理pta多选答案 初始化服务器配置 互联网不能算高科技 比亚迪软件开发前途 数据库技术类工作 城管网络安全自查报告 联想存储服务器4599电源多大 广东汇智网络技术有限公司 同学们一起来重视网络安全吧英文 超星汇雅书电子图书数据库 微信记录腾讯服务器后台保存多久 云州区机械网络安全常见问题 秦皇岛森雅网络技术 怎样保证网络安全信息不被泄露 怎么开通LOL手游的服务器 会计信息化网络安全国家政策 公司软件开发合同书 苏州专业医疗健康软件开发 小马 备份数据库 全国大学生网络安全保卫知识 mysql服务器名在哪里看
0