侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

浅谈innodb_autoinc_lock_mode的表现形式和选值参考方法

数据库  /  管理员 发布于 5年前   307

前提条件,percona 5.6版本,事务隔离级别为RR

mysql> show create table test_autoinc_lock\G*************************** 1. row ***************************    Table: test_autoinc_lockCreate Table: CREATE TABLE `test_autoinc_lock` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_a` (`a`)) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf81 row in set (0.00 sec)mysql> select * from test_autoinc_lock;+----+------+| id | a  |+----+------+| 1 |  1 || 12 |  2 || 2 |  3 || 3 |  5 || 4 |  7 || 5 |  7 || 6 |  9 || 7 |  10 |+----+------+8 rows in set (0.00 sec)

条件1 innodb_autoinc_lock_mode设置为0

session1 begin;delete from test_autoinc_lock where a>7;//这时未提交session2mysql> insert into test_autoinc_lock(a) values(100);//gap锁的存在,这时处于锁等待session3mysql> insert into test_autoinc_lock(a) values(2);//这时同样处于等待状态,理论上这个不是gap锁的锁定范围,那么它是在等什么呢session4mysql> select * from information_schema.innodb_trx\G*************************** 1. row ***************************          trx_id: 2317         trx_state: LOCK WAIT        trx_started: 2016-10-31 19:28:05   trx_requested_lock_id: 2317:20     trx_wait_started: 2016-10-31 19:28:05        trx_weight: 1    trx_mysql_thread_id: 9         trx_query: insert into test_autoinc_lock(a) values(2)    trx_operation_state: setting auto-inc lock     trx_tables_in_use: 1     trx_tables_locked: 1     trx_lock_structs: 1   trx_lock_memory_bytes: 360      trx_rows_locked: 0     trx_rows_modified: 0  trx_concurrency_tickets: 0    trx_isolation_level: REPEATABLE READ     trx_unique_checks: 1  trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000     trx_is_read_only: 0trx_autocommit_non_locking: 0

这时查看session3是等待自增锁,一直处于setting auto-inc lock状态

session2

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

这时session3锁等待超时退出

session3

这时再看session3可以发现insert完成。

mysql> select * from test_autoinc_lock;+----+------+| id | a  |+----+------+| 1 |  1 || 12 |  2 || 13 |  2 || 2 |  3 || 3 |  5 || 4 |  7 || 5 |  7 || 6 |  9 || 7 |  10 |+----+------+9 rows in set (0.00 sec)//注意看这时的最大自增值是13,也就是之前自增最大值上+1,也就是说session2后来释放了预计生成的自增id,将13留给了session3,自增id值的申请完全是串行顺序的。

结论:innodb_autoinc_lock_mode为0时的,也就是官方说的traditional

级别,该自增锁是表锁级别,且必须等待当前SQL执行完成后或者回滚掉才会释放,这样在高并发的情况下可想而知自增锁竞争是比较大的。

条件2 innodb_autoinc_lock_mode设置为1

session1mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> delete from test_autoinc_lock where a>7;Query OK, 2 rows affected (0.00 sec)mysql> select * from test_autoinc_lock;+----+------+| id | a  |+----+------+| 1 |  1 || 12 |  2 || 13 |  2 || 2 |  3 || 3 |  5 || 4 |  7 || 5 |  7 || 6 |  9 || 7 |  10 |+----+------+9 rows in set (0.00 sec)//注意看这时的最大自增值是13session2mysql> insert into test_autoinc_lock(a) values(100);//同样gap锁的存在,这时处于锁等待session3mysql> insert into test_autoinc_lock(a) values(5);Query OK, 1 row affected (0.00 sec)mysql> select * from test_autoinc_lock;+----+------+| id | a  |+----+------+| 1 |  1 || 12 |  2 || 13 |  2 || 2 |  3 || 3 |  5 || 15 |  5 || 4 |  7 || 5 |  7 || 6 |  9 || 7 |  10 |+----+------+10 rows in set (0.00 sec)//session3直接完成了,并且注意观察插入的自增id值是15,也就是跳过了预计分配给session2的14,可以看到自增id值立马就分配给了session3,而不必等session2执行完成

结论:innodb_autoinc_lock_mode为1时的,也就是官方说的consecutive

级别,这时如果是单一的insert SQL,可以立即获得该锁,并立即释放,而不必等待当前SQL执行完成(除非在其他事务中已经有session获取了自增锁)。另外当SQL是一些批量insert sql时,比如insert into ...select ...,load data,replace ..select..时,这时还是表级锁,可以理解成退化为必须等待当前SQL执行完才释放。

可以认为,该值为1时是相对比较轻量的锁,也不会对复制产生影响,唯一的缺陷是产生的自增值不一定是完全连续的(不过个人认为这个往往不是很重要,也没必要根据自增id值来统计行数之类)

条件3 innodb_autoinc_lock_mode设置为2

先说结论:当innodb_autoinc_lock_mode设置为2时,所有insert种类的SQL都可以立马获得锁并释放,这时的效率最高。但是会引入一个新的问题:当binlog_format为statement时,这时的复制没法保证安全,因为批量的insert,比如insert ..select..语句在这个情况下,也可以立马获取到一大批的自增id值,不必锁整个表,slave在回放这个sql时必然会产生错乱。我们做个测试验证复制不是安全的。

master session1mysql> show variables like '%binlog_for%';+---------------+-----------+| Variable_name | Value   |+---------------+-----------+| binlog_format | STATEMENT |+---------------+-----------+1 row in set (0.00 sec)mysql> insert into test_autoinc_lock(a) select * from test_auto;Query OK, 8388608 rows affected, 1 warning (29.85 sec)Records: 8388608 Duplicates: 0 Warnings: 1master session2(注意session2在session1执行完成之前执行)mysql> insert into test_autoinc_lock(a) values(2);Query OK, 1 row affected (0.01 sec)mysql> select * from test_autoinc_lock where a=2;+---------+------+| id   | a  |+---------+------+| 1376236 |  2 |+---------+------+1 row in set (0.00 sec)slave session1(这时可看到1376236主键冲突)mysql> show slave status\G*************************** 1. row ***************************        Slave_IO_State: Waiting for master to send event         Master_Host: 10.9.73.139         Master_User: ucloudbackup         Master_Port: 3306        Connect_Retry: 60       Master_Log_File: mysql-bin.000006     Read_Master_Log_Pos: 75823243        Relay_Log_File: mysql-relay.000002        Relay_Log_Pos: 541    Relay_Master_Log_File: mysql-bin.000006       Slave_IO_Running: Yes      Slave_SQL_Running: No       Replicate_Do_DB:      Replicate_Ignore_DB:       Replicate_Do_Table:     Replicate_Ignore_Table:    Replicate_Wild_Do_Table:  Replicate_Wild_Ignore_Table:           Last_Errno: 1062          Last_Error: Error 'Duplicate entry '1376236' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'insert into test_autoinc_lock(a) select * from test_auto'         Skip_Counter: 0     Exec_Master_Log_Pos: 75822971

我们这时解析下主库的binlog不难发现问题原因,第一条批量insert还没执行完时,第二条简单insert执行时获得了自增id值为1376236的锁,这时在主库写入是没有问题的,但是反应到从库时,因为是基于statement的复制,必然出现主键冲突。

SET INSERT_ID=1376236/*!*/;#161031 21:44:31 server id 168380811 end_log_pos 75822940 CRC32 0x65797f1c   Query  thread_id=20  exec_time=0   error_code=0use `test`/*!*/;SET TIMESTAMP=1477921471/*!*/;insert into test_autoinc_lock(a) values(2)/*!*/;# at 75822940#161031 21:44:31 server id 168380811 end_log_pos 75822971 CRC32 0xbb91449d   Xid = 274COMMIT/*!*/;# at 75822971#161031 21:44:26 server id 168380811 end_log_pos 75823050 CRC32 0xa297b57b   Query  thread_id=57  exec_time=30  error_code=0SET TIMESTAMP=1477921466/*!*/;BEGIN/*!*/;# at 75823050# at 75823082#161031 21:44:26 server id 168380811 end_log_pos 75823082 CRC32 0xa5aa31a1   IntvarSET INSERT_ID=1/*!*/;#161031 21:44:26 server id 168380811 end_log_pos 75823212 CRC32 0x470282ba   Query  thread_id=57  exec_time=30  error_code=0SET TIMESTAMP=1477921466/*!*/;insert into test_autoinc_lock(a) select * from test_auto

总结:

1 innodb row复制时,可将innodb_autoinc_lock_mode设置为2,这时可在所有insert情况下表获得最大并发度

2 innodb statement复制时,可将innodb_autoinc_lock_mode设置为1,保证复制安全的同时,获得简单insert语句的最大并发度

3 myisam引擎情况下,无论什么样自增id锁都是表级锁,设置innodb_autoinc_lock_mode参数无效(测试略)

4 实际上提问者说到的在innodb引擎下自增id值作为主键的情况下,相比uuid或者自定义的主键,是可以提到插入速度的,因为innodb是主键聚集索引,实际的主键值必须按照主键顺序存取,那么自增id本身就是升序的,那么在插入数据时,底层就不必再做额外的排序操作,也减少了索引页分裂的次数,从而大大增加insert速度(除非其他方案也能保证主键完全自增)

以上这篇浅谈innodb_autoinc_lock_mode的表现形式和选值参考方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


  • 上一条:
    bldbubg.exe是什么文件的进程 bldbubg进程安全吗
    下一条:
    innodb_index_stats导入备份数据时报错表主键冲突的解决方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客