通过shell脚本模拟MySQL自增列的不一致问题
MySQL的自增列问题其实很有意思,在重启数据库之后,会按照max(id)+1的方式来计算,这样一个看起来有些别扭的实现方式在早期版本就饱受诟病,在MySQL 5.7都没有解决掉,终于在8.0松口了,计划在这个版本中修复。
而重启会带来自增列一类的潜在问题,而如果不重启其实也有可能会有自增列的不一致问题。和两个参数table_definition_cache和table_open_cache还是密切相关的。
主要的原因是什么呢,引用阿里数据库内核团队的解释(https://www.kancloud.cn/taobaomysql/monthly/67171):一方面InnoDB表自增值是存储在表对象中的,表对象又是放在缓存中的,如果表太多而不能全部放在缓存中的话,老的表就会被置换出来,这种被置换出来的表下次再使用的时候,就要重新打开一遍,对自增列来说,这个过程就和实例重启类似,需要 select max(id) + 1 算一下自增值。
表对象缓存大小由 table_definition_cache 系统变量控制,最小值为400,表缓存相关的另一个系统变量是table_open_cache,这个控制的是所有线程打开表的缓存大小,这个缓存放在server层。
我在查看了5.6.14的环境之后,发现这个值已经提升到了500,而在MySQL 5.7中,提升到了1400,可见这方面了下了大功夫。
MySQL 5.6.14的参数值情况
# mysqladmin var|grep table_open_cache
| table_open_cache | 256
| table_open_cache_instances | 1
# mysqladmin var|grep table_definition_cache
| table_definition_cache | 500
MySQL 5.7中的参数值情况:
mysql> show variables like 'table_definition_cache';
| Variable_name | Value |
| table_definition_cache | 1400 |
mysql> show variables like 'table_open_cache';
| Variable_name | Value |
| table_open_cache | 2000 |
阿里的同学给出了testcase的伪代码,我就来实现以下,给出shell版本的测试脚本。
首先我们可以模拟一下这个测试的基线,把两个变量都修改为400.
SET GLOBAL table_definition_cache = 400;
SET GLOBAL table_open_cache = 400;
然后使用如下的shell脚本,仔细来看,脚本逻辑很简单了。
生成500个表,然后插入一条数据,修改自增列值,然后查询表里的数据,使得数据能够刷出,稍作等待,查看show create table的结果。
for i in {1..500}
do
mysql test_new <<EOF
CREATE TABLE t$i(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id)) ENGINE=InnoDB;
INSERT INTO t$i(name) VALUES("InnoDB");
ALTER TABLE t$i AUTO_INCREMENT = 100;
EOF
done
for i in {1..500}
do
mysql test_new <<EOF
SELECT * FROM t$i;
EOF
done
sleep 10;
for i in {1..3}
do
mysql test_new <<EOF
SHOW CREATE TABLE t$i;
EOF
done
测试完成之后,来查看自增列的值情况.
在5.6.14中效果很明显。
Table Create Table
t1 CREATE TABLE `t1` (n `id` int(11) NOT NULL AUTO_INCREMENT,n `name` varchar(30) DEFAULT NULL,n PRIMARY KEY (`id`)n) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
而在5.7中,发现这类问题竟然还复现不了了,至于是代码层级做了修复还是和其它参数有关,就需要深入一下了。
Table Create Table
t1 CREATE TABLE `t1` (n `id` int(11) NOT NULL AUTO_INCREMENT,n `name` varchar(30) DEFAULT NULL,n PRIMARY KEY (`id`)n) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=latin1
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ggplot2|玩转Manhattan图-你有被要求这么画吗?
- deconstructSigs|探寻cosmic的独特“气质”-mutation signature !
- barplot3d|圣诞节送你一个mutation signature搭建的“乐高”
- R读取gmt文件
- 一个画双层pie图的函数
- DEapp(差异表达分析)本地版——自由飞翔
- 盘一盘Tidyverse| 筛行选列之select,玩转列操作
- 2-14 |“特殊”的日子,多学一种表达爱的方式
- 盘一盘Tidyverse| 只要你要只要我有-filter 筛选行
- RNA相互作用神器——ENCORI
- R|tableone 快速绘制文章“表一”-基线特征三线表
- R-apply| 基因表达量批量二分类,Get!(修正版)
- TCGAbiolinks获取癌症临床信息
- R-rbind.fill|列数不一致的多个数据集“智能”合并,Get!
- R-ggpmisc|回归曲线添加回归方程,R2,方差表,香不香?