对于那些向带有自增列的表中插入行的语句,Innodb提供一种可配置的锁定机制,这种锁定机制可以显著提高SQL语句的可伸缩性和性能。
Innodb中为了使用自增机制,自增列必须是索引的部份,从而可以使用等价查询。典型的做法是将自增列放在表的索引的第一个位置。
 
Innodb自增锁模式
自增锁模式是在启动的时候由参数innodb_autoinc_lock_mode指定的。
 
在讲innodb_autoinc_lock_mode之前,先了解一下以下名词:
--"insert-like"语句
  在表中产生新行的语句,比如insert、insert...select、replace、replace...select、load data。也包含"simple-inserts"、"bulk-inserts"、"mixed-mode"插入。
 
--"simple-inserts"
  语句执行前可以提前知道要插入多少行。包含不含有子查询的单行插入、多行插入和单行replace、多行replace。但是不包含insert... on duplicate key update。
 
--"bulk inserts"
  插入的行数数量是不知道的。包含insert... select,replace...select,load data,而不是简单的插入。innodb每处理一行就给自增列指定一个新值。
 
--"mixed-mode inserts"
  类似simple-inserts,但是不是所有的自增列都被指定值。例如t1表中c1列是自增列:  
insert into t1(c1,c2) values(1,'a'),(null,'b'),(5,'c'),(null,'d')

  另一种"mixed-mode inserts"是insert...on duplicate key update,最差的场景就是一条insert后跟着一条update,产生的自增列的值可能都没有用到。

 
innodb_autoinc_lock_mode有三种配置值:0、1、2
-0表示"traditional"
  传统锁模式的行为跟5.1之前一样,即没有出现该参数的时候一样。主要是为了向后兼容,性能测试等。
  在这种模型下,insert-like语句使用表级别的auto-inc锁来插入自增值。锁通常是持有到语句结束(不是事务结束)。
  对于给定的一些列插入语句,自增值的产生是可预测和可重复有序的,且是连贯的。
 
  对于基于语句的复制,在slave端的一条语句的自增值和在master端是一样的。如果多个语句是交错的,那么slave端两个并发语句的结果可能是不一致的。
 
示例:
首先有张表:
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语句,自增值的产生不是交错的。

tx1产生的自增值是连续的,tx2中单独的自增值要么比tx1中的小,要么比其大。取决于哪个事务先执行。
 
在基于语句的复制或恢复场景,只要二进制中的sql执行是按照相同的顺序,结果就会和tx1和tx2的结果一致。所以表级锁对基于语句的复制时是安全的。但是表级锁会限制并发性和扩展性。
 
在上面的例子中,如果没有表级锁,tx2中产生的自增值的准确性取决于其运行时间,如果运行时恰好tx1也在运行,最后结果是不可确定的,多次测试的结果也是不同的。
 
在consecutive锁模式下,innodb避免了使用表级别的auto-inc锁来控制"simple-insert"语句。
如果不使用二进制日志去replay语句来恢复或者复制,可以使用"interleaved"模式的锁,从而避免使用表级auto-inc锁,而且能够支持大的并发和提升性能,代价是自增值会产生gap。
 

·1表示"consecutive"锁模式

这是默认的锁定模式。在这种模式下,“bulk inserts”使用特殊的AUTO-INC表级锁并将其保持到语句结束。这适用于所有INSERT ... SELECT,REPLACE ... SELECT和LOAD DATA语句。一次只能执行一条持有AUTO-INC锁的语句。如果批量插入操作的源表与目标表不同,则在对源表中选择的第一行加共享锁之后,将对目标表执行AUTO-INC锁。如果批量插入操作的源和目标在同一表中,则在对所有选定行施加共享锁之后,获取AUTO-INC锁。

"Simple inserts"可以提前知道需要哪些自增值,在mutex的帮助下,不需要对表加上标级auto-inc锁。mutex只是在分配自增值得时候存在,不需要等整个sql语句结束才释放。如果有另外的事务持有auto-inc锁得时候,就需要获取表级auto-inc锁了。

此锁模式可确保在存在INSERT语句的情况下(事先不知道行数)(并且随着语句的进行自动分配自增值),所有由“insert-like”语句分配的自动递增值语句是连续的,并且操作对于基于语句的复制是安全的。

简而言之,此锁模式可提高可伸缩性,同时可安全地用于基于语句的复制。此外,与“传统”锁定模式一样,任何给定语句分配的自动增量编号都是连续的。对于任何使用自增的语句,与“传统”模式相比,语义没有任何变化,但有一个重要的例外。

"mixed-mode inserts"例外,其中用户为多行"simple insert"中的某些(但不是全部)行的AUTO_INCREMENT列提供了显式值。对于此类插入,InnoDB分配的自增值比要插入的行数更多。但是,所有自动分配的值都是连续生成的(因此高于由最近执行的先前语句生成的自增值)。"多余"的自增值被丢失。

·2表示"interleaved"锁模式

在这种锁模式下,没有"insert-like"语句使用表级的AUTO-INC锁定,并且可以同时执行多个语句。这是最快,最具扩展性的锁定模式,但是当使用基于语句的复制或恢复方案从二进制日志中重放SQL语句时,这是不安全的。

在这种锁模式下,保证自增值是唯一的,并且在所有同时执行的"insert-like"语句中单调递增。但是,由于多个语句可以同时生成数字(也就是说,在语句之间交错分配数字),因此为任何给定语句插入的行生成的值可能不是连续的。

如果仅执行的语句是"insert-like",为单个语句生成的数字中没有空格。其中要提前知道要插入的行数,则为“除混合模式插入”外,为单个语句生成的数字中没有空格。但是,执行"bulk-inserts"时,任何给定语句分配的自增值可能存在间隙。

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。

MySQL -- Innodb是如何处理自增列的的更多相关文章

  1. MySQL面试题之为什么要为innodb表设置自增列做主键?

    为什么要为innodb表设置自增列做主键? 1.使用自增列做主键,写入顺序是自增的,和B+数叶子节点分裂顺序一致 2.表不指定自增列做主键,同时也没有可以被选为主键的唯一索引,InnoDB就会选择内置 ...

  2. mysql 深度解析auto-increment自增列"Duliplicate key"问题

    转载自:https://cloud.tencent.com/developer/article/1367681 问题描述 近期,线上有个重要Mysql客户的表在从5.6升级到5.7后master上插入 ...

  3. mysql iot 主键自增列问题

    mysql 如何避免热点块? 主键按sn自增列 Oracle 可以通过翻转索引 比如 插入101 102 103 104 变成101 201 301 401 分散数据 反转索引坏处,无法index r ...

  4. MySQL innodb的组合索引各个列中的长度不能超过767,

    MySQL索引的索引长度问题   MySQL的每个单表中所创建的索引长度是有限制的,且对不同存储引擎下的表有不同的限制. 在MyISAM表中,创建组合索引时,创建的索引长度不能超过1000,注意这里索 ...

  5. MySQL使用AUTO_INCREMENT列的表注意事项之update自增列篇

    1)对于MyISAM表,如果用UPDATE更新自增列,如果列值与已有的值重复,则会出错:如果大于已有的最大值,则会自动更新表的AUTO_INCREMENT,操作是安全的. (2)对于innodb表,u ...

  6. MySQL--自增列学习

    ##=====================================================================================## 在数据库表设计中会纠 ...

  7. MySQL--自增列持久化问题

    ====================================================================== 自增列持久化问题 5.5/5.6/5.7三个版本中,MyS ...

  8. [MySQL FAQ]系列 — 为什么InnoDB表要建议用自增列做主键

    我们先了解下InnoDB引擎表的一些关键特征: InnoDB引擎表是基于B+树的索引组织表(IOT): 每个表都需要有一个聚集索引(clustered index): 所有的行记录都存储在B+树的叶子 ...

  9. (转)mysql中InnoDB表为什么要建议用自增列做主键

    InnoDB引擎表的特点 1.InnoDB引擎表是基于B+树的索引组织表(IOT) 关于B+树 (图片来源于网上) B+ 树的特点: (1)所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关 ...

随机推荐

  1. Android基础(五) Service全解析----看不见的Activity

    一.服务的介绍: 作为Android四大组件之中的一个,Service(服务)也常常运用于我们的日常使用中,它与Activity的差别在于:Service一直在后台执行.没实用户界面.所以绝不会到前台 ...

  2. JQUERY验证上传文件大小

    function checkImgType(this_){ var filepath=$(this_).val(); var extStart=filepath.lastIndexOf(". ...

  3. 解决 IE6 背景缓存

    解决 IE6 背景缓存 <!--[if IE 6]><script type="text/javascript">document.execCommand( ...

  4. 微信小程序 - async/await

    下面只是做一些介绍以及使用的原因,详情介绍还请移步博主:https://www.cnblogs.com/SamWeb/p/8417940.html regenerator-runtime下载:http ...

  5. 深度学习-Caffe编译测试的小总结

    1. 搭建的环境和代码:win7 64bit + vs2013+CUDA7.5 http://blog.csdn.net/thesby/article/details/50880802 2. 编译,制 ...

  6. Windows7安装UBUNTU虚拟机

    1.下载虚拟机:http://www.orsoon.com/Soft/12192.html 2.下载UBUNTU10.04:http://releases.ubuntu.com/lucid/ 3.安装 ...

  7. JERSEY中文翻译(第一章、Getting Started、1.1.7)

    最近发现jersey特别流行,但是中文资料非常少,深感没有资料的痛苦,所以分享一下看到的内容供他人快速入门. 今天翻译第一章.Getting Started.https://jersey.java.n ...

  8. angularjs初始化时不显示模板内容, 不显示html, 不显示template

    template的内容可能在需要的数据准备好之前就显示出来了, ng-cloak可以解决这个问题 ng-cloak <div id="template1" ng-cloak& ...

  9. DUBBO本地搭建及小案例 (转)

    DUBBO的介绍部分我这里就不介绍了,大家可参考官方文档. DUBBO的注册中心安装 DUBBO的注册中心支持好几种,公司用到zookeeper注册中心,所以我这边只说明zookeeper注册中心如何 ...

  10. mybatis 于 hibernate区别

    两者区别是还是非常大的,结合至今为止的经验,总结出以下几点: 1. hibernate是全自动,而mybatis是半自动. hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的Ja ...