MySQL自增列主从不一致的测试(r12笔记第37天)

    MySQL里面有一个问题尤其值得注意,那就是自增列的重复值问题,之前也简单分析过一篇,但是在后续我想了下,还有很多地方需要解释,一个就是从库的自增列是如何维护的,是否重启从库,自增列会受到影响。

   我们继续来测试一下。首先复现这个问题。

   创建表t1,插入3行数据。

use test;
[test]> drop table if exists t1;
Query OK, 0 rows affected, 1 warning (0.01 sec)
> create table t1(id int auto_increment, a int, primary key (id)) engine=innodb;
Query OK, 0 rows affected (0.02 sec)
insert into t1 values (1,2);
insert into t1 values (null,2);
insert into t1 values (null,2);
[test]> select *from t1;               
+----+------+
| id | a    |
+----+------+
|  1 |    2 |
|  2 |    2 |
|  3 |    2 |
+----+------+因为存在3行数据,这个时候自增列的值是4.

[test]> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)我们删除id值最大的记录id=3

mysql> delete from t1 where id=3;
Query OK, 1 row affected (0.02 sec)这个时候会发现AUTO_INCREMENT=4的值不会有任何变化。

我们来挖掘一下binlog的内容,就会发现insert语句很特别。

# /usr/local/mysql_5.7.17/bin/mysqlbinlog --socket=/home/data/s1/s1.sock --port=24801 -vv  /home/data/s1/binlog.000001可以看到insert语句是MySQL独有的语法形式。
### SET
###   @1=3 /* INT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
# at 2271

delete也会基于行级变更,定位到具体的记录的方式来删除。

### DELETE FROM `test`.`t1`
### WHERE
###   @1=3 /* INT meta=0 nullable=0 is_null=0 */
###   @2=2 /* INT meta=0 nullable=1 is_null=0 */
# at 2509
我们重启一下数据库。

# mysqladmin --socket=/home/data/s1/s1.sock --port=24801 shutdown                        
# /bin/sh /usr/local/mysql_5.7.17/bin/mysqld_safe --defaults-file=/home/data/s1/s1.cnf &重启之后就会发现情况发生了变化,原来的自增值4现在变为了3,这个也是基于max(id)+1的方式来计算的。

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)这个时候我们来关注一下从库,从库的自增列值会变化吗?
mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)这个时候就会发现重启数据库以后,主从的自增列的值不同了。
那么我们来进一步测试,在主库插入一条记录,这样自增列的值就是4.

mysql> insert into t1 values (null,2);
Query OK, 1 row affected (0.01 sec)自增列的值为4,而从库的自增列的值依旧没有任何变化。

继续插入一条记录,这个时候主库的自增列就会是5

mysql> insert into t1 values (null,2);
Query OK, 1 row affected (0.00 sec)而从库呢,这个时候自增列会持续发生变化吗?我们来验证一下,这个时候从库的自增列又开始生效了。

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
还有一点需要注意,那就是指定了自增列的值,这一点上和Oracle有一定的差距,但是又很相似。
这个时候数据库主库中的数据如下:

mysql> select * from t1;
+----+------+
| id | a    |
+----+------+
|  1 |    2 |
|  2 |    2 |
|  3 |    2 |
|  4 |    2 |
|  5 |    2 |
+----+------+
5 rows in set (0.00 sec)为了方便测试,我们继续插入一条数据,这一次我指定了id值。

mysql> insert into t1 values(6,2);
Query OK, 1 row affected (0.00 sec)让人感到安慰的是,这张情况下自增列还是会持续增加。

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)此时查看从库,这个自增列也还是7,,
通过这个案例,我们能够看到在MySQL会存在这样一类问题,实际上在多环境历史数据归档的情况下,如果主库重启,很可能会出现数据不一致的情况。

  我也在MySQL的官方bug列表中看到很多人在讨论这个问题,看来很多人碰到这个坑。而这个问题其实细究起来实现也不是一个很繁琐的工作,为什么一直没有修复。

   这个问题在MySQL很久以前就有,在现在依旧存在,什么时候会修复呢,根据官方的计划会在8.0中修复。让我们拭目以待。

时间: 2024-09-29 03:44:17

MySQL自增列主从不一致的测试(r12笔记第37天)的相关文章

MySQL 5.6, 5.7并行复制测试(r12笔记第9天)

   对于主从延迟,其实一直以来就是一个颇有争议的话题,在MySQL阵营中,如果容忍一定的延迟的场景,通过主从来达到读写分离是个很不错的方案,但是延迟率到底有多高可以接受,新版本中的并行复制效果怎么样,在不同的版本中是否有改变,我们能否找到一些参考的数据来佐证,这一点上我们可以通过一些小测试来说明.    首先来为了基本按照同一个参考标准,我们就在同一台服务器上安装了5.6,5.7的MySQL服务,另外一台服务器上搭建了从库.    数据库版本为5.6.23 Percona分支, 5.7.17

深入探寻mysql自增列导致主键重复问题的原因_Mysql

废话少说,进入正题.      拿到问题后,首先查看现场,发现问题表的中记录的最大值比自增列的值要大,那么很明显,当有记录进行插入时,自增列产生的值就有可能与已有的记录主键冲突,导致出错.首先想办法解决问题,通过人工调大自增列的值,保证大于表内已有的主键即可,调整后,导数据正常.问题是解决了,接下来要搞清楚问题原因,什么操作导致了这种现象的发生呢?       这里有一种可能,即业务逻辑包含更新自增主键的代码,由于mysql的update动作不会同时更新自增列值,若更新主键值比自增列大,也会导致

MySQL自增列插入0值的解决方案_Mysql

在将数据库从MSSQL迁移到MySQL的过程中,基于业务逻辑的要求,需要在MySQL的自增列插入0值.在MSSQL中是这样完成的: 复制代码 代码如下: string sql;sql = " set identity_insert dbo.AppUsers on " + " insert dbo.AppUsers (Id, IsLocked, IsMustChangeLocalPassword, IsAvailable, Name, Sequence, CreatedBy,

sandbox和MHA快速测试(r12笔记第32天)

昨天写了一篇使用脚本搭建一主多从的脚本之后,奇龙兄建议我看看sandbox的功能,可以秒级搭建主从环境,简单试了下,确实很好很强大.    环境部署其实很简单,如果有网络环境,直接cpan一个命令即可.或者使用wget的方式来安装也可以. 安装sandbox 使用cpan来安装,非常简单,就是下面的命令: cpan MySQL::Sandbox 一些日志的输出之后就提示你安装成功,在/usr/local/bin下面就会多几个make_sandbox相关的命令. [root@grtest bin]

MySQL中的double write(二)(r12笔记第17天)

    MySQL里的double write是InnoDB的三大闪亮特性,另外两个是insert buffer 和自适应哈希,其实还有几个比如异步IO,Flush neighbour Page(刷新邻接页),这个和系统层面的关联性较高,所以三大亮点还是更有针对性的.    当然一说到MySQL里的double write,其实主要是要应对一个很自然的问题,那就是partial write. 经典的partial write问题    这个问题比较经典,很多数据库设计中都需要考虑到这样一个临界点

MySQL中的批量初始化数据的对比测试(r12笔记第71天)

  一直以来对于MySQL的存储过程性能还是颇有微词的,说实话够慢的.有时候想做一些对比测试,存储过程初始化几万条数据都得好一会儿,这功夫Oracle类似的测试早都做完了,今天就赶个晚班车,把这个没做完的任务完成了.     我大体测试了一下,以100万数据为基准,初始化性能的提升会从近8分钟提升到10多秒钟.      我自己尝试了以下4种方案.      1.存储过程批量导入(近8分钟)      2.存储过程批量导入内存表,内存表导入目标表(近5分钟)      3.使用shell脚本生成

MySQL中GTID和自增列的数据测试(r12笔记第38天)

  昨天的一篇文章,今天有不少网友向我确认一些细节,我想最近正好在看GTID的东西,可以揉在一起来说说.    GTID这个概念看似简单,实际上还是有不少的门道. 我们来从架构的设计角度来看看存在哪些场景需要考虑GTID的变化.   一主两从的架构模式下GTID的变化   我们就以一主两从的架构为基准进行阐述.在这个架构模式下我们会用到MHA的方案.    如果这个时候Master节点宕机了,MHA就会开启检查机制. 这个时候Slave 1节点就会变为新的Master,Slave 2会从Slav

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

重置 MySQL 自增列 AUTO_INCREMENT 初时值 注意, 使用以下任意方法都会将现有数据删除. 方法一: delete from tb1; ALTER TABLE tbl AUTO_INCREMENT = 100; (好处, 可以设置 AUTO_INCREMENT 为任意值开始) 提示:如果表列和数据很多, 速度会很慢, 如90多万条, 会在10分钟以上. 方法二: truncate tb1; (好处, 简单, AUTO_INCREMENT 值重新开始计数.) 怎么重置mysql的

如何做到复制表后 自增列值与原表一致

问题描述 有SQL表T1和T2(结构完全一致),用SqlDataReader将表T1所有记录添加到另一个表T2中,因T1表中的自增列有不确定的断区,T1与T2中的自增列值不一致,如何能做到T1表与T2表的自增列值一致? 解决方案 解决方案二:什么叫自增列一致,自增列不能修改的,那你不如自己设计一列,自己维护,不要自增了解决方案三:在复制之前,T2表不要设置自动递增·先设为主见即可·然后把数据导入进去之后,在设置自动递增