故障分析 | mysql 5.6 升级到 8.0 失败一例处理

本文详细记录了一次从MySQL 5.6经5.7升级到8.0过程中遇到的数据字典不一致问题,特别是由于缺失中间表文件导致的升级失败。作者通过分析错误信息、理解MySQL数据字典变化,发现孤儿表空间并尝试多种清理方法。最终,通过单机多实例的方式,实现了表空间的导出、导入和In-Place升级,成功解决了问题。

作者:付祥

现居珠海,主要负责 Oracle、MySQL、mongoDB 和 Redis 维护工作。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


1.背景

当前 zabbix 系统 mysql 版本 5.6 ,数据量有 1.5T 左右,存在按天分区的一些大表,执行添加字段操作将会非常耗时,曾经遇到过给一张几百 GB 的 history 表加一个字段,使用 pt-osc 工具,跑了
2天也没执行完;为了使用 mysql 8.0 的即时加列功能,于是决定升级到 mysql 8.0 。

2.升级过程

因为数据量比较大,采用数据逻辑导出导入方式升级将会非常慢,不推荐,故采取 In-Place 方式升级,根据官方文档提供的升级路径,需要先从 5.6 升级到 5.7 ,然后再升级到 8.0 。

从 5.6 升级到 5.7.35 非常顺利,当从 5.7.35 升级到 8.0.25 时,升级失败,报错信息如
下:

2021-07-20T07:33:18.138368Z 1 [ERROR] [MY-011006] [Server] Got error 197 from SE
while migrating tablespaces.
2021-07-20T07:33:18.145105Z 0 [ERROR] [MY-010020] [Server] Data Dictionary
initialization failed.
2021-07-20T07:33:18.145502Z 0 [ERROR] [MY-010119] [Server] Aborting
2021-07-20T07:33:40.435143Z 0 [System] [MY-010910] [Server]
/usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.25) MySQL Community
Server - GPL.

单从错误信息来看,似乎是迁移表空间失败,数据字典不能初始化,导致 mysql 不能启动,这里引发了一个问题思考:为何升级到 5.7 没问题?

3.解决过程

在错误信息不明显的情况下,降了几个 mysql 8.0 小版本升级测试,终于在 8.0.15 得到了有价值的错误提示信息:

2021-07-20T12:25:06.672826Z 1 [ERROR] [MY-011014] [Server] Found partially
upgraded DD. Aborting upgrade and deleting all DD tables. Start the upgrade
process again.
2021-07-20T12:25:06.773766Z 1 [Warning] [MY-012351] [InnoDB] Tablespace 7314,
name 'zabbix/#sql-ib104-715696445', file './zabbix/#sql-ib104-715696445.ibd' is
missing!
2021-07-20T12:25:06.834751Z 0 [ERROR] [MY-010020] [Server] Data Dictionary
initialization failed.

8.0 以前数据字典信息分布在 server 层、 mysql 库下的系统表和 InnoDB 内部系统表三个地方,数据字典分散存储, DDL 没有 原子性。

8.0 以后元数据信息全部存储在 InnoDB dictionary table 中,并且存储在单独的表空间mysql.ibd 里, DDL 具有原子性。

因为数据字典的管理存储方式发生了变化,升级到 8.0 数据字典需要做迁移转换,故 5.6->5.7 没问题, 5.7->8.0 由于缺失 ./zabbix/#sql-ib104-715696445.ibd 文件导致了升级失败。

当前环境 zabbix 数据库目录下并不存在 #sql-ib104-715696445.ibd 文件,只有一个 #sql- 开头的 frm 文件

[root@GZ-DB-6CU552YR4V zabbix]# ls -l ./#sql*
-rw-rw---- 1 mysql mysql 8808 5 9 2020 ./#sql-8427_2008.frm
[root@GZ-DB-6CU552YR4V zabbix]#

解析 frm 文件可以通过 mysqlfrm 、 dbsake ,本文通过 dbsake 解析:

./dbsake frmdump ./#sql-8427_2008.frm

-- Table structure for table `#sql-8427_2008`

-- Created with MySQL Version xxxxxx

CREATE TABLE `#sql-8427_2008` (
`eventid` bigint(20) unsigned NOT NULL,
`source` int(11) NOT NULL DEFAULT '0',
`object` int(11) NOT NULL DEFAULT '0',
`objectid` bigint(20) unsigned NOT NULL DEFAULT '0',
`clock` int(11) NOT NULL DEFAULT '0',
`value` int(11) NOT NULL DEFAULT '0',
`acknowledged` int(11) NOT NULL DEFAULT '0',
`ns` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`eventid`),
KEY `events_1` (`source`,`object`,`objectid`,`clock`),
KEY `events_2` (`source`,`object`,`clock`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=COMPRESSED;

这种看起来有点奇怪的文件是如何产生的呢?在表执行 ddl 操作时,有两种方式:

ALTER TABLE (ALGORITHM=COPY)
ALTER TABLE (ALGORITHM=INPLACE)

ALGORITHM=INPLACE 方式是 online ddl ,如果在操作过程中异常退出,将会产生以 #sql-ib 为前缀的孤儿中间表,并伴随着以 #sql- 为前缀的不同名 frm 文件。

对于 ALTER TABLE (ALGORITHM=COPY) 方式 ddl ,如果在操作过程中异常退出,将会产生以#sql- 为前缀的孤儿临时表,并伴随着以 #sql- 为前缀的同名 frm 文件。

要查询数据库是否存在孤儿表,可以查询数据字典 INFORMATION_SCHEMA.INNODB_SYS_TABLES 。

对于当前升级失败环境,根据报错信息中 Tablespace 7314 查询数据字典INFORMATION_SCHEMA.INNODB_SYS_TABLES ,发现并不存在以 #sql 开头的表,但是在information_schema.INNODB_SYS_DATAFILES 、 INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES中却有相关记录,也就是说数据字典记录的元数据信息之间产生了不一致:

root@3306 (none)> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%#sql%';
Empty set (0.01 sec)

root@3306 (none)> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES whereSPACE=7314;
Empty set (0.00 sec)

[root@3306][(none)]> select * from information_schema.INNODB_SYS_DATAFILES where space=7314;
+-------+-----------------------------------+
| SPACE | PATH |
+-------+-----------------------------------+
| 7314 | ./zabbix/#sql-ib104-715696445.ibd |
+-------+-----------------------------------+
1 row in set (0.01 sec)

[root@3306][(none)]> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE =7314;
+-------+-----------------------------+------+-------------+------------+--------
---+---------------+------------+---------------+-----------+----------------+
| SPACE | NAME | FLAG | FILE_FORMAT | ROW_FORMAT |
PAGE_SIZE | ZIP_PAGE_SIZE | SPACE_TYPE | FS_BLOCK_SIZE | FILE_SIZE |
ALLOCATED_SIZE |
+-------+-----------------------------+------+-------------+------------+--------
---+---------------+------------+---------------+-----------+----------------+
| 7314 | zabbix/#sql-ib104-715696445 | 41 | Barracuda | Compressed |
16384 | 8192 | Single | 0 | 0 | 0
|
+-------+-----------------------------+------+-------------+------------+--------
---+---------------+------------+---------------+-----------+----------------+
1 row in set (0.01 sec)

那如何清理孤儿表呢?参考官方文档:
https://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting-datadict.html

给出的解决方案前提是 INFORMATION_SCHEMA.INNODB_SYS_TABLES 存在相关元数据信息,显然和当前环境还不一样,故通过 DROP TABLE #mysql50##sql-ib104-715696445 方式清理孤儿中间表失
败。通过删表方式不行,那通过删库方式是否可行呢?大致步骤如下:

  1. create database zabbix_new;
  2. alter table zabbix.xxxxxx rename to zabbix_new.xxxxxx;
  3. drop database zabbix;
  4. SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE =7314;

经过测试,即使删除了zabbix库,残留的元数据 #sql-ib104-715696445.ibd 依然存在。

数据字典存放在共享表空间 ibdata1 中,要解决此问题,只有绕过 ibdata1 文件,想到的有如下两种方案:

3.1. 逻辑导出导入升级到 mysql 8.0

常用的工具有 mysqldump 、 mydumper ,其中 mydumper 支持按表并发,能极大提升效率

3.2. 传输表空间+ In-Place 升级到 mysql 8.0

因为没有其他机器提供及磁盘空间也不充足,故采取单机多实例进行表空间传输,大致步骤如下:

  1. 导出用户信息及zabbix元数据
mysqldump -uroot -p -B mysql -E -R --triggers --hex-blob --set-gtid-purged=off -- single-transaction --master-data=2 >zabbix-metadata-01.sql
mysqldump -uroot -p -B zabbix -E -R --triggers --hex-blob --no-data --set-gtid- purged=off --single-transaction --master-data=2 >zabbix-metadata-02.sql
  1. 初始化一个5.7版本3307端口实例并启动

  2. 加载用户信息及zabbix元数据

mysql -h127.0.0.1 -P3307 -uroot -p < zabbix-metadata-01.sql
mysql> flush privileges;
mysql -h127.0.0.1 -P3307 -uroot -p < zabbix-metadata-02.sql
  1. 新实例zabbix库丢弃表空间
mysql -uroot -p -NBe "select concat('alter table ',TABLE_NAME,' discard tablespace;') from information_schema.TABLES where TABLE_SCHEMA='zabbix'";
use zabbix;
set foreign_key_checks=0;
alter table xxxxxx discard tablespace;
  1. 干净的关闭原来mysql实例,并移动zabbix库下 ibd 文件到新实例对应路径,如果空间充足,最好保留原文件,通过 cp 方式
mv /data/3306/zabbix/*.ibd /data/3307/zabbix/
  1. 导入表空间,这一步也比较费时,因为需要修改 ibd 文件中页的 space id 和数据字典 space id 一致等操作
alter table xxxxxx import tablespace;

导入表空间时,需要数据字典定义的 row format 和 ibd 文件中记录的 row format 一致,否则将报错:

ERROR 1808 (HY000): Schema mismatch (Table has ROW_TYPE_DYNAMIC row format, .ibd file has ROW_TYPE_COMPACT row format.)

通过 alter table xxxxxx row_format=compact 修改行格式,第5步 mv 过来的 ibd 文件会被删除,导致数据丢失,故要先 mv 走 ibd 文件再修改 row format

mv /data/3307/zabbix/acknowledges.ibd /data/3307/zabbix/acknowledges.ibd.bak alter table acknowledges row_format=compact;
mv /data/3307/zabbix/acknowledges.ibd.bak /data/3307/zabbix/acknowledges.ibd alter table acknowledges import tablespace;
  1. In-Place 方式升级新实例到 8.0
<think>好的,用户现在遇到了MySQL的1293错误,并想了解如何升级MySQL来解决这个问题。首先,我需要回顾之前的对话,确保这次的回答与之前的信息一致,同时补充用户的新需求,即升级MySQL的步骤。 首先,用户之前的问题是关于错误1293的解决方案,我之前给出了三种方法:显式定义默认值、调整字段顺序和升级MySQL 5.7+。现在用户进一步询问如何升级MySQL,所以需要详细说明升级步骤。 接下来,用户提供的引用中提到了MySQL 5.7的错误汇总和另一个系统级别的错误,但看起来这些引用可能太相关。需要忽略这些相关的引用,专注于用户的实际需求:解决1293错误和升级MySQL。 用户现在明确表示想解决1293错误,并了解如何升级MySQL。我需要确认当前的解决方案是否仍然适用,尤其是升级MySQL 5.7或更高版本的步骤是否准确。 需要注意,用户在之前的问题中可能已经尝试过部分解决方案,比如修改表结构,但可能没有成功,所以现在考虑升级升级MySQL是一个有效的解决方案,因为MySQL 5.7及以上版本确实移除了这个限制。 在回答中,需要分步骤说明如何升级,包括备份数据、停止服务、添加新源、安装新版本、启动服务、验证版本等步骤。同时,要提醒用户升级前备份数据的重要性,以及可能遇到的依赖问题,特别是同操作系统(如Ubuntu、CentOS)的处理方法。 另外,用户可能对升级过程中的具体命令熟悉,所以需要给出具体的命令示例,比如使用apt-get或yum进行安装,以及如何选择版本。同时,需要提到升级后可能需要运行mysql_upgrade来更新系统表。 还需要确保回答中的引用标记正确,根据之前的回答,引用[^1]、[^4]、[^5]已经涉及到了版本差异和解决方案,所以在升级部分可以适当引用这些来源。 最后,用户可能需要了解升级后的验证步骤,比如如何检查新版本,以及如何修改表结构以使用多个TIMESTAMP字段。需要确保这部分内容清晰,让用户能够按步骤操作。 总结来说,回答需要包括: 1. 错误1293的简要回顾和原因。 2. 升级MySQL的详细步骤,分同操作系统。 3. 升级后的验证和表结构修改示例。 4. 注意事项和备份提醒。 5. 相关问题的扩展,帮助用户深入理解。</think>### 深度解析:MySQL错误1293与升级解决方案 --- #### 错误核心原因 MySQL错误1293的根本原因在于**版本限制**: - **MySQL 5.6及以下版本**严格限制一个表中只能有一个$TIMESTAMP$字段使用$DEFAULT\ CURRENT\_TIMESTAMP$或$ON\ UPDATE\ CURRENT\_TIMESTAMP$[^1][^4] - 若尝试定义多个字段同时使用时间戳自动更新功能,例如: ```sql CREATE TABLE test ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); ``` 将直接触发错误1293,因为两个字段均涉及$CURRENT\_TIMESTAMP$逻辑[^5]。 --- #### 终极解决方案:升级MySQL 5.7+ ##### 升级步骤(以Ubuntu/CentOS为例) 1. **备份数据** 使用`mysqldump`全量备份,避免升级失败导致数据丢失: ```bash mysqldump -u root -p --all-databases > full_backup.sql ``` 2. **停止MySQL服务** ```bash systemctl stop mysql # Ubuntu/Debian systemctl stop mysqld # CentOS/RHEL ``` 3. **添加新版MySQL源** - **Ubuntu**: ```bash wget https://dev.mysql.com/get/mysql-apt-config_0.8.22-1_all.deb dpkg -i mysql-apt-config_0.8.22-1_all.deb apt-get update ``` - **CentOS**: ```bash rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-6.noarch.rpm yum clean all && yum makecache ``` 4. **安装新版本MySQL** ```bash # Ubuntu/Debian apt-get install mysql-server=8.0.* # 指定版本号 # CentOS/RHEL yum install mysql-community-server ``` 5. **启动服务并验证版本** ```bash systemctl start mysql mysql -V # 输出应显示MySQL 8.0.x或5.7.x ``` 6. **修复系统表** ```bash mysql_upgrade -u root -p ``` --- #### 升级后验证与表结构调整 1. **检查MySQL版本** ```sql SELECT VERSION(); -- 预期输出:5.7.x 或 8.0.x ``` 2. **重建表结构** ```sql ALTER TABLE your_table MODIFY created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, MODIFY updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; ``` 3. **测试自动更新功能** ```sql UPDATE your_table SET column_name = 'new_value' WHERE id = 1; SELECT updated_at FROM your_table WHERE id = 1; -- 时间应自动更新 ``` --- #### 关键注意事项 1. **版本兼容性** - MySQL 8.0默认启用`explicit_defaults_for_timestamp`参数,需确保其值为`OFF`以兼容旧版行为: ```sql SET GLOBAL explicit_defaults_for_timestamp = OFF; ``` 2. **依赖冲突处理** 若遇到类似`libssl.so.1.1: cannot open shared object file`的错误,需手动安装依赖: ```bash wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb dpkg -i libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb ``` --- ### 相关问题 1. **如何在停机的情况下升级MySQL?** 2. **MySQL 8.0的时间戳行为与5.7有何同?** 3. **如何回滚失败MySQL升级操作?** 通过升级可彻底解决1293错误,并享受性能优化和新特性支持[^4][^5]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值