`

关于mysql auto_increment所带来的锁表操作

 
阅读更多

以前内容主要是对官方文档中的意译,并加入了一些自己的理解(新版本还是很给力的)。侯哥原创,欢迎交流。

详细参照官方文档:http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-increment-configurable

在mysql5.1.22之前,mysql的“INSERT-like”语句(包INSERT, INSERT...SELECT, REPLACE,REPLACE...SELECT, and LOAD DATA)会在执行整个语句的过程中使用一个AUTO-INC锁将表锁住,直到整个语句结束(而不是事务结束)。因此在使用INSERT...SELECT、INSERT...values(...),values(...)时,LOAD DATA等耗费时间较长的操作时,会将整个表锁住,而阻塞其他的“INSERT-like”、Update等语句,推荐使用程序将这些语句分成多条语句,一一插入,减少单一时间的锁表时间,荣嬷嬷的superdump就不错。

mysql5.1.22之后mysql进行了改进,引入了参数 innodb_autoinc_lock_mode,通过这个参数控制mysql的锁表逻辑,在介绍这个之前先引入几个术语,方便说明 innodb_autoinc_lock_mode。

1.“INSERT-like”:

INSERT, INSERT ... SELECT, REPLACE, REPLACE ... SELECT, and LOAD DATA, INSERT ... VALUES(),VALUES()

2.“Simple inserts”

就是通过分析insert语句可以确定插入数量的insert语句, INSERT, INSERT ... VALUES(),VALUES()

3.“Bulk inserts”

就是通过分析insert语句不能确定插入数量的insert语句, INSERT ... SELECT, REPLACE ... SELECT, LOAD DATA

4.“Mixed-mode inserts”

下面两种,不确定是否需要分配auto_increment id

INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

INSERT ... ON DUPLICATE KEY UPDATE

 

一、innodb_autoinc_lock_mode = 0 (“traditional” lock mode)

这种方式就和mysql5.1.22以前一样,为了向后兼容而保留了这种模式,如同前面介绍的一样,这种方式的特点就是“表级锁定”,并发性较差

二、innodb_autoinc_lock_mode = 1 (“consecutive” lock mode)

这种方式是新版本中的默认方式,推荐使用,并发性相对较高,特点是“consecutive”,即保证同一条insert语句中新插入的auto_increment id都是连续的。

这种模式下:

“Simple inserts”:直接通过分析语句,获得要插入的数量,然后一次性分配足够的auto_increment id,只会将整个分配的过程锁住。

“Bulk inserts”:因为不能确定插入的数量,因此使用和以前的模式相同的表级锁定。

“Mixed-mode inserts”:直接分析语句,获得最坏情况下需要插入的数量,然后一次性分配足够的auto_increment id,只会将整个分配的过程锁住。需要注意的是,这种方式下,会分配过多的id,而导致”浪费“。比如INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');会一次性的分配5个id,而不管用户是否指定了部分id;INSERT ... ON DUPLICATE KEY UPDATE一次性分配,而不管将来插入过程中是否会因为duplicate key而仅仅执行update操作。

注意:当master mysql版本<5.1.22,slave mysql版本>=5.1.22时,slave需要将innodb_autoinc_lock_mode设置为0,因为默认的innodb_autoinc_lock_mode为1,对于INSERT ... ON DUPLICATE KEY UPDATE和INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');的执行结果不同,现实环境一般会使用INSERT ... ON DUPLICATE KEY UPDATE。

三、innodb_autoinc_lock_mode = 2 (“interleaved” lock mode)

这种模式是来一个分配一个,而不会锁表,只会锁住分配id的过程,和innodb_autoinc_lock_mode = 1的区别在于,不会预分配多个,这种方式并发性最高。但是在replication中当binlog_format为statement-based时(简称SBR statement-based replication)存在问题,因为是来一个分配一个,这样当并发执行时,“Bulk inserts”在分配的时会同时向其他的INSERT分配,会出现主从不一致(从库执行结果和主库执行结果不一样),因为binlog只会记录开始的insert id。

测试SBR,执行begin;insert values(),();insert values(),();commit;会在binlog中每条insert values(),();前增加SET INSERT_ID=18/*!*/;。

但是row-based replication RBR时不会存在问题。

另外RBR的主要缺点是日志数量在包括语句中包含大量的update delete(update多条语句,delete多条语句)时,日志会比SBR大很多;假如实际语句中这样语句不是很多的时候(现实中存在很多这样的情况),推荐使用RBR配合innodb_autoinc_lock_mode,不过话说回来,现实生产中“Bulk inserts”本来就很少,因此innodb_autoinc_lock_mode = 1应该是够用了。

下面是官方文档举得几个例子,这里就不翻译的

For example, assume c1 is an AUTO_INCREMENT column of table t1, and that the most recent automatically generated sequence number is 100. Consider the following “mixed-mode insert” statement:

 

INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

With innodb_autoinc_lock_mode set to 0 (“traditional”), the four new rows will be:

 

+-----+------+

| c1  | c2   |

+-----+------+

|   1 | a    |

| 101 | b    |

|   5 | c    |

| 102 | d    |

+-----+------+

The next available auto-increment value will be 103 because the auto-increment values are allocated one at a time, not all at once at the beginning of statement execution. This result is true whether or not there are concurrently executing “INSERT-like” statements (of any type).

 

With innodb_autoinc_lock_mode set to 1 (“consecutive”), the four new rows will also be:

 

+-----+------+

| c1  | c2   |

+-----+------+

|   1 | a    |

| 101 | b    |

|   5 | c    |

| 102 | d    |

+-----+------+

However, in this case, the next available auto-increment value will be 105, not 103 because four auto-increment values are allocated at the time the statement is processed, but only two are used. This result is true whether or not there are concurrently executing “INSERT-like” statements (of any type).

 

With innodb_autoinc_lock_mode set to mode 2 (“interleaved”), the four new rows will be:

 

+-----+------+

| c1  | c2   |

+-----+------+

|   1 | a    |

|   x | b    |

|   5 | c    |

|   y | d    |

+-----+------+

The values of x and y will be unique and larger than any previously generated rows. However, the specific values of x and y will depend on the number of auto-increment values generated by concurrently executing statements.

 

Finally, consider the following statement, issued when the most-recently generated sequence number was the value 4:

 

INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

With any innodb_autoinc_lock_mode setting, this statement will generate a duplicate-key error 23000 (Can't write; duplicate key in table) because 5 will be allocated for the row (NULL, 'b') and insertion of the row (5, 'c') will fail.

分享到:
评论

相关推荐

    MySQL AUTO_INCREMENT 主键

    - 当表中存在`AUTO_INCREMENT`字段时,应该确保其列的数据类型能够容纳所需的唯一值范围。 - 如果`AUTO_INCREMENT`字段类型太小,可能会导致溢出错误,从而影响数据完整性。 - 在进行批量插入或并发插入操作时,应...

    MySQL 序列 AUTO_INCREMENT详解及实例代码

    MySQL 序列 AUTO_INCREMENT详解及实例代码 MySQL序列是一组整数:1, 2, 3, …,由于一张数据表只能有一个字段自增主键, 如果你想实现其他字段也实现自动增加,就可以使用MySQL序列来实现。 本章我们将介绍如何使用...

    python mysql自增字段AUTO_INCREMENT值的修改方式

    在处理MySQL数据库时,经常需要操作自增字段(AUTO_INCREMENT),尤其是当需要调整自增起始值的时候。在Python中与MySQL交互时,了解如何修改AUTO_INCREMENT的值是十分重要的。本文将深入探讨如何在使用Python操作...

    Mysql auto_increment 重新计数(让id从1开始)

    在MySQL数据库中,`auto_increment` 是一个非常重要的特性,它允许在插入新记录时自动为某个整数字段(通常是主键)生成唯一的递增值。当你清空一个具有`auto_increment`字段的表,然后重新插入数据时,可能会发现这...

    MySQL查询和修改auto_increment的方法

    在MySQL数据库中,`...通过理解并熟练掌握这些查询和修改`auto_increment`的方法,可以更有效地管理和维护MySQL数据库中的表,确保数据的完整性和一致性。在实际工作中,务必谨慎操作,避免对数据造成不必要的影响。

    解析mysql中的auto_increment的问题

    MySQL中的auto_increment是一种非常实用的属性,用于为表中的记录自动生成唯一的ID。这通常用于主键字段,确保每条记录都可以通过一个唯一的标识符进行区分。然而,auto_increment在处理记录删除、数据库重启以及...

    04_auto_increment—MYSQL相关应用

    04_auto_increment.avi MYSQL应用 MYSQL视频 MYSQL教程,讲解中连接上一集03集

    怎么重置mysql的自增列AUTO_INCREMENT初时值

    在MySQL数据库中,自增列(AUTO_INCREMENT)是一种非常有用的特性,它允许表中的某列在插入新记录时自动递增其值。当你需要重置这个初始值时,可能是因为数据库进行了一些清理操作或者需要从特定数值开始重新计数。...

    mysql中自增auto_increment功能的相关设置及问题

    请注意,如果`auto_increment_offset`的值大于`auto_increment_increment`,则`auto_increment_offset`会被忽略。 3. **自增行为** 当插入新记录时,系统会基于当前的`auto_increment_offset`和`auto_increment_...

    关于MySQL innodb_autoinc_lock_mode介绍

    MySQL的InnoDB存储引擎在处理带有`auto_increment`列的表时,会受到`innodb_autoinc_lock_mode`参数的影响。这个参数决定了插入数据时如何管理自动递增锁,从而在性能和数据安全性(主从数据一致性)之间取得平衡。 ...

    blog_auto_increment

    在数据库管理中,自动递增(Auto Increment)是一个非常重要的概念,尤其在关系型数据库如MySQL、PostgreSQL、SQLite等中广泛使用。 在MySQL中,`AUTO_INCREMENT`关键字用于定义整数列,当插入新行时,如果未指定该...

    mysql 双向同步的键值冲突问题的解决方法

    总的来说,解决MySQL双向同步中的键值冲突问题,关键在于利用`auto_increment_offset`和`auto_increment_increment`参数,合理规划每个服务器的自增长ID序列,以确保数据的一致性和完整性。同时,为了保证整个系统的...

    mysql.rar_MySQL Visual C++_MySql查询_c语言mysql_mysql c语言_mysql操作

    char *sql = "CREATE TABLE IF NOT EXISTS Employees (ID INT AUTO_INCREMENT PRIMARY KEY, Name CHAR(20), Position CHAR(20));"; if (mysql_query(conn, sql)) { fprintf(stderr, "%s\n", mysql_error(conn)); } ...

    mongoid_auto_increment_id:将ID字段覆盖到MySQL,例如Mongoid的自动增量

    像MySQL一样,将Mongoid id字段更改为Integer的宝石。 MongoDB文档中的想法: 注意! 这个宝石已经帮助超过了4年,并产生了超过一百万行,这是非常...gem 'mongoid_auto_increment_id' , "0.6.1" # Mongoid 3.1.x gem

    mysql_test_c__by_wy.rar_MYSQL_mysql api_mysql c++

    const char* create_table_sql = "CREATE TABLE IF NOT EXISTS students (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), age INT)"; if (mysql_query(conn, create_table_sql)) { fprintf(stderr, "%s\n",...

    oracle迁移mysql自增序列问题

    MySQL提供了两个系统变量来控制自增字段的行为:`auto_increment_offset`和`auto_increment_increment`。前者用于设置自增字段的初始值,后者用于设置自增的步长。例如,要设置自增字段从10开始,每次增加5,可以...

Global site tag (gtag.js) - Google Analytics