导读:在使用MySQL建表时,咱们一般会建立一个自增字段(AUTO_INCREMENT),并以此字段做为主键。本篇文章将以问答的形式讲述关于自增id的一切。mysql
注: 本文所讲的都是基于Innodb
存储引擎。sql
InnoDB
会选择主键做为汇集索引、若是没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的惟一索引做为主键索引、若是也没有这样的惟一索引,则InnoDB会选择内置6字节长的ROWID做为隐含的汇集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。综上而言:当咱们使用自增列做为主键时,存取效率是最高的。缓存
自增id是增加的 不必定连续。测试
咱们先来看下MySQL 对自增值的保存策略:优化
InnoDB 引擎的自增值,实际上是保存在了内存里,而且到了 MySQL 8.0 版本后,才有了“自增值持久化”的能力,也就是才实现了“若是发生重启,表的自增值能够恢复为 MySQL 重启前的值”,具体状况是:code
在 MySQL 5.7 及以前的版本,自增值保存在内存里,并无持久化。每次重启后,第一次打开表的时候,都会去找自增值的最大值 max(id),而后将 max(id)+1 做为这个表当前的自增值。索引
举例来讲,若是一个表当前数据行里最大的 id 是 10,AUTO_INCREMENT=11。这时候,咱们删除 id=10 的行,AUTO_INCREMENT 仍是 11。但若是立刻重启实例,重启后这个表的 AUTO_INCREMENT 就会变成 10。事务
也就是说,MySQL 重启可能会修改一个表的 AUTO_INCREMENT 的值。内存
在 MySQL 8.0 版本,将自增值的变动记录在了 redo log 中,重启的时候依靠 redo log 恢复重启以前的值。rem
形成自增id不连续的状况可能有:
自增id是整型字段,咱们经常使用int类型来定义增加id,而int类型有上限 即增加id也是有上限的。
下表列举下 int
与 bigint
字段类型的范围:
类型 | 大小 | 范围(有符号) | 范围(无符号) |
---|---|---|---|
int | 4字节 | (-2147483648,2147483647) | (0,4294967295) |
bigint | 8字节 | (-9223372036854775808,9223372036854775807) | (0,18446744073709551615) |
从上表能够看出:当自增字段使用int有符号类型时,最大可达2147483647即21亿多;使用int无符号类型时,最大可达4294967295即42亿多。固然bigint能表示的范围更大。
下面咱们测试下当自增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 '4294967295' for key 'PRIMARY'
从实验能够看出,当自增id达到最大时将没法扩展,第一个 insert 语句插入数据成功后,这个表的AUTO_INCREMENT 没有改变(仍是 4294967295),就致使了第二个 insert 语句又拿到相同的自增 id 值,再试图执行插入语句,报主键冲突错误。
维护方面主要提供如下2点建议: