背景

应用端需要生成依次递增的序列来做流水序号等,方案有1、redis /MySQL SEQUENCE引擎生成序列;2、MySQL中myisam表 replace into方式;3、MySQL中innodb表INSERT ... ON DUPLICATE KEY方式

分析

  • redis /MySQL SEQUENCE引擎生成序列,但多个MySQL集群都有生成序列的需求,若出问题,影响范围大;redis /MySQL SEQUENCE中生成序列也增加了研发修改代码的成本,新项目可以使用这种方式

  • MySQL中myisam表 replace into 是我们目前使用生成序列的方式(虽然是表锁,每秒生成的序列也满足得了需求),使用方式为
  1. CREATE TABLE `test_sequence` (
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  3. `val` tinyint(1) DEFAULT '0',
  4. PRIMARY KEY (`id`),
  5. UNIQUE KEY `val` (`val`)
  6. ) ENGINE=MyISAM;
  7. >replace into test_sequence(val) values(99);
  8. Query OK, 1 row affected (0.00 sec)
  9. >select last_insert_id();
  10. +------------------+
  11. | last_insert_id() |
  12. +------------------+
  13. | 1 |
  14. +------------------+
  15. 1 row in set (0.00 sec)
  16. >replace into test_sequence(val) values(99);
  17. Query OK, 2 rows affected (0.00 sec)
  18. >select last_insert_id();
  19. +------------------+
  20. | last_insert_id() |
  21. +------------------+
  22. | 2 |
  23. +------------------+
  24. 1 row in set (0.00 sec)

但存在问题:

myisam表非事务存储引擎,备份存在不一致(恢复还原数据有不一致风险);

myisam也不是crash-safe的;

gtid模式下,同一个事务中不能操作myisam表和innodb表

为什么不用innodb表replace into方式了?

该方式并发大时,存在发生死锁的风险


  • MySQL中事务性 innodb表INSERT ... ON DUPLICATE KEY,是crash-safe ,看起来myisam生成序列的存在的问题它都没有!实际情况了?

    使用方式:
  1. CREATE TABLE `test_sequence2` (
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  3. `val` tinyint(1) DEFAULT '0',
  4. PRIMARY KEY (`id`),
  5. UNIQUE KEY `val` (`val`)
  6. ) ENGINE=InnoDB;
  7. 00>insert into test_sequence2(val) values(99) on duplicate key update id=id+1;
  8. Query OK, 1 row affected (0.00 sec)
  9. 39>select id from test_sequence2;
  10. +---------+
  11. | id |
  12. +---------+
  13. | 1 |
  14. +---------+
  15. 1 row in set (0.00 sec)
  16. 22>insert into test_sequence2(val) values(99) on duplicate key update id=id+1;
  17. Query OK, 2 rows affected (0.00 sec)
  18. 25>select id from test_sequence2;
  19. +---------+
  20. | id |
  21. +---------+
  22. | 2 |
  23. +---------+
  24. 1 row in set (0.00 sec)

测试

普通机械磁盘机器

MySQL5.7.16

RR隔离级别

sysbench 自定义sql语句测试tps(每秒生成多少序列)

  • myisam replace into 方式
  1. cd /usr/share/sysbench/tests
  2. sysbench ./test_myisam.lua --mysql-host=127.0.0.1 --mysql-port=3701 --mysql-db=test --mysql-user=sysbench --mysql-password=sysbench --tables=1 --threads=10 --time=30 --report-interval=5 run
  • innodb INSERT ... ON DUPLICATE KEY UPDATE方式
  1. cd /usr/share/sysbench/tests
  2. sysbench ./test_innodb.lua --mysql-host=127.0.0.1 --mysql-port=3701 --mysql-db=test --mysql-user=sysbench --mysql-password=sysbench --tables=1 --threads=10 --time=30 --report-interval=5 run
myisam replace into innodb insert..on duplicate
1并发线程 124 tps 122 tps
10并发线程 123 tps 121 tps
20并发线程 125 tps 104 tps
30并发线程 127 tps 67 tps
40并发线程 127 tps 33 tps
  • 可见myisam随着并发线程数的增加,replace into tps保持不变,原因是myisam是表锁,同一时刻,该表只能写或者只能读
  • innodb表随着并发数的上升,insert..on duplicate tps不升反降,行锁之前的争用变大了 造成锁等待
  • 本次测试机器配置差,结果有些参考性,线上机器配置更好

注意 mysqlslap 压测innodb表40个并发线程时可能会出现死锁(RC隔离级别也是),死锁详细见最后

为什么sysbench40 并发线程测试没有出现过死锁?难道sysbench并发线程不是同一时刻发出的?_

  1. /usr/local/mysql/bin/mysqlslap -usysbench -h127.0.0.1 -P3701 -p --concurrency=40 --iterations=1 --create-schema=test --query='insert into test_sequence2(val) values(99) on duplicate key update id=id+1;select id from test_sequence2;'
  2. /usr/local/mysql/bin/mysqlslap: Cannot run query insert into test_sequence2(val) values(99) on duplicate key update id=id+1;select id from test_sequence2; ERROR : Deadlock found when trying to get lock; try restarting transaction

结论

  • myisam表 replace into生成序列是稳定的方法,不管并发线程数多少,生成序列速度是稳定的,但myisam表存在缺陷问题
  • innodb表 inert on duplicate 生成序列适合并发线程数少情况,并发线程数多会出现死锁 生成序列速度下降情况
  • 若要求生成序列的速度快,可用redis /MySQL SEQUENCE方式

死锁日志

  1. LATEST DETECTED DEADLOCK
  2. ------------------------
  3. 2020-02-11 11:03:11 0x7f6a0c643700
  4. *** (1) TRANSACTION:
  5. TRANSACTION 39260727, ACTIVE 1 sec inserting
  6. mysql tables in use 1, locked 1
  7. LOCK WAIT 28 lock struct(s), heap size 3520, 26 row lock(s), undo log entries 1
  8. MySQL thread id 460828, OS thread handle 140093451958016, query id 21296424 127.0.0.1 root update
  9. insert into test_sequence2(val) values(99) on duplicate key update id=id+1
  10. *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
  11. RECORD LOCKS space id 48 page no 4 n bits 72 index val of table `test`.`test_sequence2` trx id 39260727 lock_mode X waiting
  12. Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
  13. 0: len 1; hex e3; asc ;;
  14. 1: len 8; hex 000000000000001a; asc ;;
  15. *** (2) TRANSACTION:
  16. TRANSACTION 39260729, ACTIVE 1 sec updating or deleting, thread declared inside InnoDB 5000
  17. mysql tables in use 1, locked 1
  18. 29 lock struct(s), heap size 3520, 27 row lock(s), undo log entries 1
  19. MySQL thread id 460835, OS thread handle 140093451155200, query id 21296425 127.0.0.1 root update
  20. insert into test_sequence2(val) values(99) on duplicate key update id=id+1
  21. *** (2) HOLDS THE LOCK(S):
  22. RECORD LOCKS space id 48 page no 4 n bits 72 index val of table `test`.`test_sequence2` trx id 39260729 lock_mode X
  23. Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
  24. 0: len 1; hex e3; asc ;;
  25. 1: len 8; hex 000000000000001a; asc ;;
  26. *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
  27. RECORD LOCKS space id 48 page no 3 n bits 168 index PRIMARY of table `test`.`test_sequence2` trx id 39260729 lock_mode X waiting
  28. Record lock, heap no 37 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
  29. 0: len 8; hex 000000000000001b; asc ;;
  30. 1: len 6; hex 000002571237; asc W 7;;
  31. 2: len 7; hex b6000001680110; asc h ;;
  32. 3: len 1; hex e3; asc ;;
  33. *** WE ROLL BACK TRANSACTION (1)

自定义sysbench脚本

less test_myisam/innodb.lua

  1. require("oltp_common")
  2. function thread_init(thread_id)
  3. drv=sysbench.sql.driver()
  4. con=drv:connect()
  5. end
  6. function event(thread_id)
  7. local vid1
  8. local dbprefix
  9. con:query('replace into test_sequence(val) values(99)')
  10. con:query('select last_insert_id()')
  11. ##innodb insert..on duplicate 语句
  12. #con:query('insert into test_sequence2(val) values(99) on duplicate key update id=id+1')
  13. #con:query('select id from test_sequence2;')
  14. end
  15. function thread_done()
  16. con:disconnect()
  17. end

MySQL MyISAM和Innodb表生成序列的更多相关文章

  1. Mysql MyISAM与InnoDB 表锁行锁以及分库分表优化

    一. 两种存储引擎:MyISAM与InnoDB 区别与作用 1. count运算上的区别: 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需 ...

  2. mysql myisam转innodb的2种方法

      mysql myisam转innodb的2种方法 mysql中的myisam和innodb有什么区别.一个好比便利店,一个好比大型购物中心,他们是为了适应不同的场合而存在的.当流量比较小,我们可以 ...

  3. MySQL MyISAM和InNodb备份与恢复技巧

    1. 为什么要备份数据库 对数据库来说,最重要也最容易被忽视的就是备份.由于不可预测性,偶然的事件可能会导致非常惨重的损失. 数据越是重要,数据的变化越频繁,备份越发需要经常进行. 备份周期根据不同业 ...

  4. MySql MyISAM和InnoDB的区别

    MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的 顺序访问方法) 的缩写,它是存储记录和文件的标准方法. ...

  5. 深入浅出分析MySQL MyISAM与INNODB索引原理、优缺点、主程面试常问问题详解

    本文浅显的分析了MySQL索引的原理及针对主程面试的一些问题,对各种资料进行了分析总结,分享给大家,希望祝大家早上走上属于自己的"成金之路". 学习知识最好的方式是带着问题去研究所 ...

  6. 深入浅出分析MySQL MyISAM与INNODB索引原理、优缺点分析

    本文浅显的分析了MySQL索引的原理及针对主程面试的一些问题,对各种资料进行了分析总结,分享给大家,希望祝大家早上走上属于自己的"成金之路". 学习知识最好的方式是带着问题去研究所 ...

  7. MYSQL MyISAM与InnoDB对比

    1. 区别: (1)事务处理: MyISAM是非事务安全型的,而InnoDB是事务安全型的(支持事务处理等高级处理): (2)锁机制不同: MyISAM是表级锁,而InnoDB是行级锁: (3)sel ...

  8. 【mysql】关于InnoDB表text blob大字段的优化

    最近在数据库优化的时候,看到一些表在设计上使用了text或者blob的字段,单表的存储空间已经达到了近100G,这种情况再去改变和优化就非常难了 一.简介 为了清楚大字段对性能的影响,我们必须要知道i ...

  9. MySQL如何判别InnoDB表是独立表空间还是共享表空间

    InnoDB采用按表空间(tablespace)的方式进行存储数据, 默认配置情况下会有一个初始大小为10MB, 名字为ibdata1的文件, 该文件就是默认的表空间文件(tablespce file ...

随机推荐

  1. SetTimeout()多次运行函数后越来越快的问题

    问题原因很简单,但是由于代码逻辑问题,一直没有考虑到: 网上有个帖子说的很明白:原帖入口 假如你在0时刻点击了一下按钮,那么500ms时数字会跳一下,1000ms会再跳一下,依次类推,1500,200 ...

  2. 设计模式-12组合模式(Composite Pattern)

    1.模式动机 很多时候会存在"部分-整体"的关系,例如:大学中的部门与学院.总公司中的部门与分公司.学习用品中的书与书包.在软件开发中也是这样,例如,文件系统中的文件与文件夹.窗体 ...

  3. js事件委托target

    **看一看,瞧一瞧!** 话说要谈事件委托和target.那我们首先来看看什么是事件.话说什么是事件呢?一般的解释是比较重大.对一定的人群会产生一定影响的事情.而在JavaScript中就不是这样了, ...

  4. Flutter 拖拽控件Draggable看这一篇就够了

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 Draggable系列组件可以让我们拖动组件. Dragg ...

  5. 关于form表单:hover没有修改表单子元素样式

    原来在写todolist的时候遇到的一个问题 是关于form表单的hover属性设置背景颜色 想要实现的效果如下: 但是一开始直接给form加hover选择器的时候是这样: 可以看到这样子直接加会使得 ...

  6. 19.10.11学习日记随笔 mysql事务隔离性

    一天的感悟 学习事务的处理方式,其中反想自己学过的flask 默认是开启事务的,flask_sqlalchemy每次在提交时都是需要commit,或者失败是需要rollback回滚操作的,其实pyth ...

  7. 代号为 Kyria 的 Manjaro Linux 19.0 系统正式发布

    Xfce版本仍然是主打,此版本Xfce更新到4.14,并且主要致力于在桌面和窗口管理器上完善用户体验. KDE版本提供了功能强大.成熟且丰富的Plasma 5.17桌面环境,此版本进行了完全重新设计. ...

  8. LeetCode 41,一题解读in-place思想

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode题解系列第21篇,今天来看一道人狠话不多的题目. 题面 题目非常简单,只有一句话,给定一个整数数组,要求返回最小的不在 ...

  9. vux中表单验证,在提交时自动聚焦到未验证通过的那栏;及循环表单的验证

    首先vux中的表单验证在点击触发,失焦时才显示错误信息,如果不管它,它就没反应,这显然是不合理的:解决办法就是:在提交时做验证,不通过的话就使用.focus()及.blur()方法给它聚焦,失焦. i ...

  10. HTTP中主要的头字段

    HTTP中主要的头字段 头字段类型 含义 备注 通用头:适用于请求和响应消息的头字段 Date 表示请求和响应生成的日期   Pragma 表示数据是否允许缓存的通信选项   Cache-Contro ...