悲剧啊!Mysql的上古BUG!!!
| 导读 | 这是MySQL8.0修复的上古bug之一,在2003年由Percona的CEO(当时应该还没Percona吧)提出的bug#199,光看这bug号就扑面而来一股上古时代的沧桑气息。 |

问题的本质在于InnoDB初始化AUTO_INCREMENT的方式,在每次重启时,总是算出表上最大的自增值作为最大值,下一次分配从该值开始。这意味着如果在btree右侧叶节点大量删除记录,重启后,自增值可能被重用。这在很多场景下可能导致问题,包括但不限于:主备切换、历史数据迁移等场景。在bug#199下面一大堆的回复里,可以看到大量的同行抱怨。
官方的修复就比较优雅了,不改变任何现有的存储,而是通过redo log来进行恢复。该补丁基于WL#7816的框架实现的,要想搞懂这个补丁,得先看看WL#7816做了哪些改动,为了解决这个问题,InnoDB使用一个引擎私有的系统表+特殊redo log的方式,在引擎内部自己解决corruption标记持久化的问题。其大概思路为:
- 当发现索引损坏时,写入一条redo log,但不更新数据词典
- 引入一个innodb引擎私有的系统表,称为DD Buffer Table,每次checkpoint之前会将索引corruption bit存入其中。
- 在崩溃恢复时,同时从redo log和DD Buffer Table中读取索引 corruption bit, 合并结果,并标记内存中的表和索引对象。
目前Persister的类型仅有两种,一个用于corruption bit的持久化,一个用于自增列的持久化,对应的类为:
Persister:
|-- CorruptedIndexPersister
|-- AutoIncPersister
Persister对应全局对象dict_persist_t::persisters,可以通过类型persistent_type_t来找到对应的Persister,目前仅有PM_INDEX_CORRUPTED及PM_TABLE_AUTO_INC,但从注释来看,未来肯定会做更多的扩展,Persister在启动时调用函数dict_persist_init进行初始化。
新的系统表名为SYS_TABLE_INFO_BUFFER,对应管理类为DDTableBuffer,指针存储在dict_persist->table_buffer中。
系统表包含两个列:TABLE_ID及BLOB类型的METADATA(ref DDTableBuffer::init),METADATA列包含了所有需要持久化的元数据。
有几种情况会将内存修改回写到DDTableBuffer中:
- 在做checkpoint(log_checkpoint)之前,所有在dirty_dict_tables链表上的表对象,对应persist metadata都需要回写到DDTableBuffer中(dict_persist_to_dd_table_buffer)
- 从内存中驱逐一个表对象时(dict_table_remove_from_cache_low),如果需要的话也会去尝试回写。
- 在对包含自增列的表做DDL后,需要持久化counter,在如下函数中,会调用dict_table_set_and_persist_autoinc:
ha_innobase::commit_inplace_alter_table
create_table_info_t::initialize_autoinc()
// for example: alter table..auto_increment = ??
row_rename_table_for_mysql;
// rename from temporary table to normal table
回写的过程也比较简单(dict_table_persist_to_dd_table_buffer_low):
- 通过表对象初始化需要回写的Metadata数据: corrupt index及autoinc值(dict_init_dynamic_metadata)
- 构建记录值,插入DDTableBuffer系统表(DDTableBuffer::replace(), 如果记录存在的话,则进行悲观更新操作
- 表对象的diry_status修改成 METADATA_BUFFERED,表示有buffer的元数据
在崩溃恢复时,当解析到日志MLOG_TABLE_DYNAMIC_META时(MetadataRecover::parseMetadataLog),会进行解析并将解析得到的数据存储到集合中(MetadataRecover::m_tables),如果存在相同table-id的项,就进行替换,确保总是最新的。
在完成recovery后,搜集到的meta信息暂时存储到srv_dict_metadata中, 随后进行apply(srv_dict_recover_on_restart), apply的过程也比较简单,载入表对象,然后对表对象进行更新(MetadataRecover::apply),例如对于autoinc列,就总是选择更大的那个值。
这个bug已经挂了相当长的时间,不排除把这个bug当作InnoDB的“特性”的同学,一定要注意到这个改动...

悲剧啊!Mysql的上古BUG!!!的更多相关文章
- 一个MySQL JDBC驱动bug引起的血案
1.1 问题背景 公司是做电商系统的,整个系统搭建在华为云上.系统设计的时候,考虑到后续的用户和订单数量比较大,需要使用一些大数据库的组件.关系型数据库这块,考虑到后续数据量的快速增长,不是 ...
- "Cannot convert value '0000-00-00' from column 2 to TIMESTAMP"mysql时间转换bug
今天在项目中遇到这样的一个bug,Cannot convert value '0000-00-00' from column 2 to TIMESTAMP 仔细一查,经过http://blog.csd ...
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(八)mysql中文查询bug修复
写在前面的话 在测试搜索时出现的问题,mysql通过中文查询条件搜索不出数据,但是英文和数字可以搜索到记录,中文无返回记录.本文就是写一下发现问题的过程及解决方法.此bug在第一个项目中点这里还存在, ...
- mysql 5.6 bug
https://dev.mysql.com/doc/refman/5.6/en/account-management-sql.html USE mysql; SELECT Host,User FROM ...
- 【MySQL 线上 BUG 分析】之 多表同字段异常:Column ‘xxx’ in field list is ambiguous
一.生产出错! 今天早上11点左右,我在工作休息之余,撸了一下猫.突然,工作群响了,老大在里面说:APP出错了! 妈啊,这太吓人了,因为只是说了出错,但是没说错误的信息.所以我赶紧到APP上看看. 这 ...
- 分享2个近期遇到的MySQL数据库的BUG案例
近一个月处理历史数据问题时,居然连续遇到了2个MySQL BUG,分享给大家一下,也欢迎指正是否有问题. BUG1: 数据库版本: MySQL5.7.25 - 28 操作系统: Centos 7.7 ...
- MySQL 的一个Bug?
在 my.ini 中的 [mysqld] 段设置 mysql basedir 和 datadir,如下: #Path to installation directory. All paths are ...
- Powser Design 16.5 导入Mysql数据库的bug
在Power Designer 16.5中,想导入mysql的某个数据库,选择导入后会导入全部数据库. 解决方案: 打开powerdesigner.选择file--->reverse engin ...
- MySql 参数赋值bug (MySql.Data, Version=6.9.6.0 沙雕玩意)
直接将参数赋值为常量0则参数值为null,出现异常:MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'PayType' canno ...
随机推荐
- Windows远程连接Linux
目录 xrdp方式 vnc方式 xrdp方式 ----------------------------------------------------------------------------- ...
- mac上设置新版chrome浏览器跨域
设置方法 打开一个新的可跨域的chrome窗口实现方法: 1. 打开终端 2. 输入下面的命令( 需要替换路径中的yourname ) open -n /Applications/Google\ Ch ...
- 基于C/S架构的3D对战网络游戏C++框架_04客户端详细设计与OpenGL、Qt基础
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- Openfire 集群部署和负载均衡方案
Openfire 集群部署和负载均衡方案 一. 概述 Openfire是在即时通讯中广泛使用的XMPP协议通讯服务器,本方案采用Openfire的Hazelcast插件进行集群部署,采用Hapro ...
- 0104探究MySQL优化器对索引和JOIN顺序的选择
转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...
- [转]ExtJs基础--Html DOM、Ext Element及Component三者之间的区别
要学习及应用好Ext框架,必须需要理解Html DOM.Ext Element及Component三者之间的区别. 每一个HTML页面都有一个层次分明的DOM树模型,浏览器中的所有内容都有相应的DOM ...
- Switch重构处理
public class Fun{ public void IFNumberid(int flag) { switch (flag) { : Console.WriteLine("优秀&qu ...
- 关于mybatis中mapper.xmlSQL语句书写的心得
本文主要针对MySQL ---------------------------------------------------------------------------------------- ...
- Canvas电子签名和游戏化
今天一天的时间都在做包团报价的无流程原型设计,一方面参考了其他系统,一方面整理先在系统中不合理的部分,规范了报价元素的分类.梳理了意向需求,其实原来粗略的放了一个模板进去是听不靠谱的.客户的要求-&g ...
- 织梦多语言站点,{dede:include filename=''/}引入问题
织梦模板include插入非模板目录文件出现"无法在这个位置找到"错误的解决办法 以下是dede V55_UTF8 查dede include标签手册 (3) include 引入 ...