45 MySQL自增id

表定义自增id

说到自增id,前面提到mysql的自增id不连续,当表定义的自增值达到上限后的逻辑是:再申请下一个id时,得到的值保持不变

create table t(id int unsigned auto_increment primary key) auto_increment=4294967295;
insert into t values(null);
// 成功插入一行 4294967295
show create table t;
/* CREATE TABLE `t` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4294967295;
*/ insert into t values(null);
//Duplicate entry '' for key 'PRIMARY

2^32-1 不是一个特别大的数,对于一个频繁插入删除数据的表来说,是可能用完的,因此在建表的时候需要观察这个表是否有可能达到这个上限,如果有可能,则需要建成8个字节的bigint unsigned.

--mysql
BIGINT[(M)] [UNSIGNED] [ZEROFILL]
A large integer. The signed range is -9223372036854775808 to 9223372036854775807. The
unsigned range is 0 to 18446744073709551615.
SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE NO_UNSIGNED_SUBTRACTION
By default, subtraction between integer operands produces an UNSIGNED result if any operand
isUNSIGNED. When NO_UNSIGNED_SUBTRACTION is enabled, the subtraction result is signed, even
if any operand is unsigned. For example, compare the type of column c2 in table t1 with that of
column c2 in table t2:
mysql> SET sql_mode='';
mysql> CREATE TABLE test (c1 BIGINT UNSIGNED NOT NULL);
mysql> CREATE TABLE t1 SELECT c1 - 1 AS c2 FROM test;
mysql> DESCRIBE t1;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| c2 | bigint(21) unsigned | | | 0 | |
+-------+---------------------+------+-----+---------+-------+
mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION';
mysql> CREATE TABLE t2 SELECT c1 - 1 AS c2 FROM test;
mysql> DESCRIBE t2;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| c2 | bigint(21) | | | 0 | |
+-------+------------+------+-----+---------+-------+
mysql> SET sql_mode = '';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| 18446744073709551615 |
+-------------------------+
mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| -1 |
+-------------------------+

Innodb系统自增row_id

如果创建的innodb的表没有显式指定主键,那么innodb会创建一个不可见的,长度为6字节的row_id,innodb维护了一个全局的dict_sys.row_id值,所有没有主键的innodb表,没插入一行数据,都将当前的dict_sys.row_id值作为要插入数据的row_id,然后把该值加1.

实际上,在代码实现是row_id是一个长度为8个字节的无符号长整形(bigint unsigned),但是,innodb在设计时,给row_id留的只是6个字节的长度,这样写到数据库表中时只放入了后6个字节,两个特征:

--1 row_id写入表中的范围,0到2^48-1

--2 当dict_sys.row_id=2^48时,如果再有插入数据的行为要来申请row_id,拿到以后再取后6个字节的话就是0,继续循环。

Xid

在答疑文章1中,日志和索引相关问题,介绍了redo log和binlog相配合的时候,提到了它们有一个共同的字段叫做Xid,它在mysql中是用来对应事务的

Mysql内部维护了一个全局变量global_query_id,每次执行语句的时候将它赋值给query_id,然后这个变量加1,如果当前语句是这个事务执行的第一个语句,那么mysql还会同时把query_id赋值给这个事务的xid

而global_query_id是一个纯内存变量, 重启之后就清零了,所以,在同一个数据库实例汇总,不同事务的xid也有可能相同的。

但是mysql重启后,会生成新的binlog文件,这就保证了,同一个binlog文件中,xid是唯一的。

但是如果global_query_id达到上限就会继续从0开始,从理论上讲,就会出现同一个binlog文件中出现相同的xid,因为global_query_id定义的长度是8个字节,上限是2^64-1,理论上回出现这个同一个binlog,相同的xid出现。

Innodb trx_id

Xid是有server层维护的,innodb内部使用xid为了能够在innodb事务和server之间做联系,但是,innodb的trx_id,是另外维护的,事务id。

Innodb内存维护了一个max_trx_id全局变量,每次需要申请一个新的trx_id时,就获得max_trx_id的当前值,并加1.

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

对于正在执行的事务,可以通过information_schema.innodb_trx看到trx_id

(system@127.0.0.1:3306) [test]> select trx_id,trx_mysql_thread_id from information_schema.innodb_trx;

SESSION A

SESSION B

begin;

select * from t limit 1;

select trx_id,trx_mysql_thread_id from information_schema.innodb_trx;

insert into t values('2018-4-2',2);

select trx_id,trx_mysql_thread_id from information_schema.innodb_trx;

Session a开始是一个只读事务,对于只读事务,innodb并不会分配trx_id,trx_id就是0,但是有一个很大的数,只是显示用的,在insert的时候,事务才真正分配了trx_id

只读事务不分配trx_id

--1 可以减小事务视图里面活跃事务数组的大小,因为当前正在运行的只读事务,是不影响数据的可见性判断的,所以,在创建事务的一致性视图时,innodb就只需要拷贝只读事务的trx_id

--2 可以减少trx_id的申请次数,普通的select语句不申请trx_id,大大减少了并发事务申请trx_id的锁冲突。

max_trx_id会持久化存储,重启也不会重置为0,那么从理论上讲,只要一个mysql服务跑得足够久,就可能出现max_trx_id达到2^48-1的上限,然后从0开始的情况。

当达到这个状态后,mysql就会持续出现一个脏读的bug。事务的可见性就根据trx_id来进行比较的。

thread_id

线程id(thread_id),线程id才是mysql中最常见的一种自增id,平时在show processlist里面的第一列,就是thead_id,系统保存了一个全局变量thread_id_counter,每新建一个连接,就讲thread_id_counter赋值给这个新连接的线程变量。

thread_id_counter定义的大小是4个字节,因此达到2^32-1后,就会重置为0,然后继续增加,但是不会在show processlist中看到两个相同的thread_id。

45 MySQL自增id的更多相关文章

  1. MySQL自增ID 起始值 修改方法

    在mysql中很多朋友都认为字段为AUTO_INCREMENT类型自增ID值是无法修改,其实这样理解是错误的,下面介绍mysql自增ID的起始值修改与设置方法. 通常的设置自增字段的方法: 创建表格时 ...

  2. Mysql自增ID起始值修改

    在mysql中很多朋友都认为字段为AUTO_INCREMENT类型自增ID值是无法修改,其实这样理解是错误的,下面介绍mysql自增ID的起始值修改与设置方法.通常的设置自增字段的方法:创建表格时添加 ...

  3. mysql自增id归0

    mysql自增id归0 ALTER TABLE table_name AUTO_INCREMENT=1;

  4. mysql自增id超大问题查询

    引言 小A正在balabala写代码呢,DBA小B突然发来了一条消息,"快看看你的用户特定信息表T,里面的主键,也就是自增id,都到16亿了,这才多久,在这样下去过不了多久主键就要超出范围了 ...

  5. 基于MySQL自增ID字段增量扫描研究

    目录 目录 1 1. 问题 1 2. 背景 1 3. InnoDB表 2 3.1. 自增ID为主键 2 3.2. 自增ID为普通索引 4 3.3. 原因分析 7 4. MyISAM表 8 4.1. 自 ...

  6. mysql 自增id

    在开发的时候遇到了 自增id变成2147483647 莫名其妙 然后发现是自己没把自增id改为 无符号的原因 把无符号勾上就ok了

  7. mysql自增id获取失败

    php 数据库pdo对象,如果是返回,如以下伪代码 function getData(){ return $data; } $data = getData(); $id = $data->las ...

  8. mysql自增ID

    InnoDB引擎的表,执行清空操作之后,表的auto_increment值不会受到影响:一旦重启MySQL,auto_increment值将变成1. MyISAM引擎的表,执行清空操作之后,表的aut ...

  9. 设置(更改)Mysql 自增ID的起始值

    SELECT * FROM segwords WHERE id>790511 DELETE FROM segwords WHERE id>790511 #下面这句是设置的 ALTER TA ...

随机推荐

  1. 方法签名_spring aop_around

    //注解签名 方法签名 Signature signature = pjp.getSignature(); MethodSignature methodSignature= (MethodSignat ...

  2. 防抖&节流

    使用的原因 在前端开发当中有一部分的用户行为会频繁操作触发事件执行,而对于DOM操作,资源加载等耗费性能的处理,很可能导致页面卡顿,甚至浏览器崩溃,函数节流和防抖就是解决类似需求应运而生的 节流 预定 ...

  3. Python 进程之间共享数据(全局变量)

    进程之间共享数据(数值型): import multiprocessing def func(num): num.value=10.78 #子进程改变数值的值,主进程跟着改变 if __name__= ...

  4. mplayer - Linux下的电影播放器

    概要 mplayer [选项] [ 文件 | URL | 播放列表 | - ] mplayer [全局选项] 文件1 [特定选项] [文件2] [特定选项] mplayer [全局选项] {一组文件和 ...

  5. Candidate Generation and LUNA16 preprocessing

    在这个kernel中,我们将讨论有助于更好地理解问题陈述和数据可视化的方法. 我还将提供有用的资源和信息的链接. 此脚本是用Python编写的. 我建议人们在桌面上安装anaconda,因为here提 ...

  6. python 编码解码

    一种编码想要转成另一种编码,需要先解码成万国码:Unicode,然后再从Unicode转成其他编码. 例如GBK格式想要转成utf-8,需要先按照 gbk 的格式 decode 成 unicode,再 ...

  7. git 流程 rebase rename

    git流程: git init --bare git checkout -b develop git checkout -b feature1 feature1: git add . git comm ...

  8. RouterOS基础安装配置

    安装 光盘安装 载入光盘,按"A"全选按"I"进行安装,然后提示不否用旧的配置,按"N"全新安装,警告时按"Y"确定 安 ...

  9. MySQL数据库3分组与单表、多表查询

    目录 一.表操作的补充 1.1null 和 not null 1.2使用not null的时候 二.单表的操作(import) 2.1分组 2.1.1聚合函数 2.1.2group by 2.1.3h ...

  10. Quantitative Strategies for Achieving Alpha(一)

    1. 怎么构建测试 所有的测试五等分,表明我们的回测的universe被分为五个组,根据我们要测试的公司因子的值. Quintiles provide a clear answer to that q ...