insert into t1(c1,c2) values(1,'a'),(null,'b'),(5,'c'),(null,'d')
另一种"mixed-mode inserts"是insert...on duplicate key update,最差的场景就是一条insert后跟着一条update,产生的自增列的值可能都没有用到。
create table t1( c1 int(11) not null auto_increment, c2 varchar(10) default null, primary key(c1) ) engine = innodb;
tx1: insert into t1 (c2) select 1000 rows from another table ... #事务1插入1000行 tx2: insert into t1 (c2) values ('xxx');
innodb无法提前知道tx1会插入多少条数据,只好每插入一条数据就产生一个自增值。对于表级锁,每次执行执行一条sql语句,所以对于不同的sql语句,自增值的产生不是交错的。
-1表示"consecutive"锁模式
这是默认的模式。在连续模式下,"bulk inserts"使用特殊的auto-inc表级别锁,直到事务结束才会释放锁。也使用于所有insert...select、replace...select、load data语句。每次只有一个sql语句可以持有该锁并执行。
如果批量插入的原表和目标表不同,当在源表上加上一个共享锁取出一条数据后,就会对目标表加上auto-inc表。如果二者相同,取完源表上的所有数据后,才会对目标表加上auto-inc锁。
"Simple inserts"可以提前知道需要哪些自增值,在mutex的帮助下,不在需要对表加上auto-inc锁。mutex只是在分配自增值得时候存在,不需要等整个sql语句结束才释放。如果有另外的事务持有auto-inc锁得时候,就需要获取表级auto-inc锁了。
这种锁模式,可以保证在插入的行数不能提前确定的时候,"insert-like"的插入语句的自增值是连续的,同时保证基于语句的复制是安全的。
-2表示"interleaved"锁模式
该模式下,所有insert-like语句都不使用表级auto-inc锁,多个语句可以同时执行。这是最快、最可扩展的模式。。
但是对基于语句的复制是不安全的,对基于语句的恢复也是不安全的。
自增列的值会被保证是唯一的。因为并发插入的原因,每次插入时,自增长的值可能不是连续的。对基于语句的复制也是不安全的。
Innodb自增锁的使用
1.使用自增列进行复制
如果使用基于语句的复制,innodb_autoinc_lock_mode设置为0或1(主、备都使用相同的配置)。如果是设置为2或者主备设置不一样,不能保证准备端一致。
如果是使用基于行的、混合模式的复制,所有自增锁模式都是安全的,因为基于行的复制对sql的执行顺序是不敏感的(混合模式会将基于语句的不安全的复制转换成行复制)。
2.自增值的丢失和序列空隙(sequence gaps)
在所有自增锁模式中(0,1,2),如果使用自增值得事务发生了回滚,这些自增值就丢失了。这些值是不可以重用的,这样就产生了gap。
3.自增列指定null或0值
在所有自增锁模式中(0,1,2),如果将自增列指定为null或0,innodb会自行给自增列赋值
4.自增列指定为负值
可以插入赋值,但是不能在负值得基础上进行自增
5.超过自增列指定的最大值
超过自增列指定的最大值就不能自增了。
6."mixed-mode inserts"中自增值得使用
"mixed-mode inserts"中有"simple insert"指定的自增值,也有没有指定的。在不同的自增锁模式下结果是不同的。
7.在插入的过程中修改自增值
会导致重复的值。
Innodb自增计数器的初始化
创建了自增列后,对应的数据字典中包含一个自增计数器,用来为列赋值。这个计数器是存储在内存中,而不是磁盘上。
在实例启动后,innodb会执行类似下面的语句来为计数器初始化:
select max(ai_col) from table_name for update;
缺省情况下,会将获取的值增加1。也可以修改参数auto_increment_increment进行配置。
如果表是空的,计数器的值就是1。