MySQL -- Innodb是如何处理自增列的

摘要:
为了在Innodb中使用自动递增机制,自动递增列必须是索引的一部分,以便可以使用等效的查询。典型的做法是将自动递增列放置在表索引的第一个位置。Innodb自增锁定模式通过Innodb参数_ autoinc_ lock_ mode激活自增锁定。innodb每次处理一行时,都会为自动递增列分配一个新值。在非特定锁模式下,innodb避免使用表级auto-inc锁来控制“简单插入”语句。对于这种类型的插入,InnoDB分配的自增量比要插入的行数更多。然而,当执行“批量插入”时,分配给属性的任何自增量中都可能存在间隙。
对于那些向带有自增列的表中插入行的语句,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是如何处理自增列的》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇架构使用vuex结合vue-meta实现router动态设置meta标签perl weixin webwxbatchgetcontact 接口下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【指导】SonarQube 部署说明

转载:https://blog.csdn.net/cuiaamay/article/details/52057091 1,安装 1.1 安装依赖 需要保证Oracle JRE 8 及以上,或者 OpenJDK 8及以上(如下安装 openjdk): # add-apt-repository ppa:openjdk-r/ppa # apt-get upd...

docker离线安装zabbix+grafana

第一部分:下载安装zabbix所须的镜像 所须镜像包为:mysql、zabbix-server、zabbix-web-nginx、zabbbix-agent 1、搜索镜像 docker search [想要搜索的镜像名] [root@localhost ~]# docker search mysql INDEX NAME...

B14-iOS开发中的几种存储方式

一、NSUserDefault(偏好设置,Preference) 小规模数据,弱业务相关数据使用。例:某个UISwitch的状态。 二、File(文件存储) 文件存储包括了Plist、archive、Stream等方式,一般结构化的数据或者需要方便查询的数据,都会以Plist的方式去持久化。 Archive方式适合存储平时不太经常使用但很大量的数据,或者读...

oracle中游标的使用

oracle中的游标,游标的概念与作用,游标的分类,游标的使用。 一,游标的概念与作用    摘自百度百科:游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行前进或向后浏览数据的能力。可以把游标当作一个指针,它可以指定结果中的任何位置,然后允许用户对指定位置的数据进行处理。游标实际上是一种能从包括...

EFCore扩展Select方法(根据实体定制查询语句)

EFCore扩展Select方法(根据实体定制查询语句)  通常用操作数据库的时候查询返回的字段是跟 我们的定义的实体是不一致的,所以往往针对UI或者接口层创建大量的Model, 而且需要手动对应字段,非常繁琐。 本文将通过表达式树解决这些重复的过程。  先贴上实现代码   Queryable 类中 的扩展方法  Select<TSource, T...

MYSQL 命令行工具自动登录的方法

MYSQL 命令行工具自动登录的方法 1. 需求提出 由于在linux 环境下,经常需要使用mysql(command-line tool) 终端连接到MYSQL DB服务。 其中大致的语法如下: mysql [options] db_name 比较重要的option 参数有: --database=db_name, -D db_name --host=...