引言
MySQL中auto_increment字段估计你们都常常用到,特别是innodb引擎。我也常常用,只知道mysql能够保证这个字段在多进程操做时的原子性,具体原理又是什么,后来查阅了MySQL手册以及相关资料,了解了个大概。
本文只探究了mysql5.5中innodb引擎auto_increment的问题。mysql
定义
- 使用auto_increment的字段可能生成惟一的标识。
如何使用
- 可在建表时可用“AUTO_INCREMENT=n”选项来指定一个自增的初始值。
- 可用alter table table_name AUTO_INCREMENT=n命令来重设自增的起始值。
使用规范
- AUTO_INCREMENT是数据列的一种属性,只适用于整数类型数据列。
- 设置AUTO_INCREMENT属性的数据列应该是一个正数序列,因此应该把该数据列声明为UNSIGNED,这样序列的编号个可增长一倍。
- AUTO_INCREMENT数据列必须有惟一索引,以免序号重复(便是主键或者主键的一部分)。
- AUTO_INCREMENT数据列必须具有NOT NULL属性。
- AUTO_INCREMENT数据列序号的最大值受该列的数据类型约束,如TINYINT数据列的最大编号是127,如加上UNSIGNED,则最大为255。一旦达到上限,
AUTO_INCREMENT就会失效。
- 当进行全表删除时,MySQL AUTO_INCREMENT会从1从新开始编号。全表删除的意思是发出如下两条语句时:
delete from table_name;
或者
truncate table table_name
原理(这里面是重点)
传统auto_increment原理
- mysql innodb引擎的表中的auto_increment字段是经过在内存中维护一个auto-increment计数器,来实现该字段的赋值,注意自增字段必须是索引,并且是索引的第一列,不必定要是主键。例如我如今在个人数据库test中建立一个表t,语句以下:
CREATE TABLE `t_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
- 则字段a为auto_increment类型,在mysql服务器启动后,第一次插入数据到表t_test时,InnoDB引擎会执行等价于下面的语句:
SELECT MAX(id) FROM t FOR UPDATE;
- Innodb获取到当前表中id字段的最大值并将增长1(默认是增长1,若是要调整为增长其余数目,能够设置auto_increment_increment这个配置的设置)而后赋值给该列以及内存中该表对应的计数器
|
在传统的auto_increment设置中,每次访问auto-increment计数器的时候, INNODB都会加上一个名为AUTO-INC锁直到该语句结束(注意锁只持有到语句结束,不是事务结束).AUTO-INC锁是一个特殊的表级别的锁,用来提高包含auto_increment列的并发插入性能.所以,两个事务不能同时获取同一个表上面的AUTO-INC锁,若是持有AUTO-INC锁太长时间可能会影响到数据库性能(好比INSERT INTO t1... SELECT ... FROM t2这类语句). |
改进后
基于上面传统方式的问题(性能太差),在mysql5.1开始,新增长了一个配置项innodb_autoinc_lock_mode来设定auto_increment方式.
能够设置的值为0,1,2.其中0就是第一节中描述的传统auto_increment机制,而1和2则是新增长的模式,默认该值为1,能够中mysql配置文件中修改该值.这里主要来看看这两种新的方式的差异;sql
在描述差异前须要先明确几个插入类型:数据库
- simple inserts
可以肯定具体的插入行数的语句。
- bulk inserts
事先没法肯定插入行数的语句
- mixed-mode inserts
有些行指定了auto_increment列的值有些没有指定
下面看看设置innodb_autoinc_lock_mode为不一样值时的状况:安全
- innodb_autoinc_lock_mode=0(traditional lock mode)
传统的auto_increment机制,这种模式下全部针对auto_increment列的插入操做都会加AUTO-INC锁,分配的值也是一个个分配,是连续的,正常状况下也不会有间隙(固然若是事务rollback了这个auto_increment值就会浪费掉,从而形成间隙)。
- innodb_autoinc_lock_mode=1(consecutive lock mode)
这种状况下,针对bulk inserts才会采用AUTO-INC锁这种方式,而针对simple inserts,则采用了一种新的轻量级的互斥锁来分配auto_increment列的值。固然,若是其余事务已经持有了AUTO-INC锁,则simple inserts须要等待.
须要注意的是,在innodb_autoinc_lock_mode=1时,语句之间是可能出现auto_increment值的间隔的。好比mixed-mode inserts以及bulk inserts中都有可能致使一些分配的auto_increment值被浪费掉从而致使间隙。后面会有例子。
- innodb_autoinc_lock_mode=2(interleaved lock mode) 这种模式下任何类型的inserts都不会采用AUTO-INC锁,性能最好,可是在同一条语句内部产生auto_increment值间隙。此外,这种模式对statement-based replication也不安全。