这个问题是线上遇到的问题,BUG有关,遇到后可能导致SQL运行缓慢,导致大量的慢查询,进而影响线上业务,还是需要警惕。
一、被关闭的自动统计数据收集
首先MySQL 8.0默认全部使用persist统计数据(innodb_stats_persistent=ON),统计数据放到mysql.innodb_table_stats和mysql.innodb_index_stats表中,内存中使用table->stat_n_rows等信息表示,正常情况下是先改内存,在写入表中,重启后会使用表的信息初始化内存信息,
一般情况下是同步的。但是mysqldump可能导致信息不同步,并且损坏mysql.innodb_table_stats和mysql.innodb_index_stats表中的信息。
一般情况下,如果修改量超过当前统计数据行数的1/10,则需要收集统计数据,会推给后台收集线程进行统计数据收集。
但是在以下的情况下会使用/*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */ 关闭自动统计数据的收集,也就是导入的时候插入数据不触发自动统计数据收集,
- 导出database包含mysql库
- 导出使用--all-databases(主要)
- 导出包含mysql.innodb_table_stats和mysql.innodb_index_stats表
这个函数为is_innodb_stats_tables_included,定义了这种行为,并且用trae分析了一下也得到了同样的结果,如下,


而就是这个原因导致了统计数据的丢失,我们继续分析。
二、统计信息丢失
这里存在2个问题点如下,包含统计数据的内存信息和持久化表,
1、 虽然导入的时候会导入innodb_table_stats表,但是语句执行的时候使用的是table->stat_n_rows的内存信息,因为前面说的自动统计数据收集已经关闭,因此无法得到更改,
(gdb) p prebuilt->table->stat_n_rows
$4 = 0
2、虽然导入的时候会导入innodb_table_stats表,然后执行drop table/create table,接着insert 数据,但是持久化的信息也会被create table 覆盖掉innodb_table_stats中的信息,因此innodb_table_stats表中的统计信息会为0,而insert 数据由于关闭了自动统计数据收集,因此不会自动收集统计数据,这样导致数据导入完成后innodb_table_stats中大量的0,也就是没有统计信息。
三、测试
这里使用8023进行测试,同时测试8041都是一样的结果,注意持久化统计数据中mytest的统计信息。
导入前
mysql> desc select count(*) from mytest ;
+----+-------------+--------+------------+-------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------+---------+------+-------+----------+-------------+
| 1 | SIMPLE | mytest | NULL | index | NULL | id | 5 | NULL | 65920 | 100.00 | Using index |
+----+-------------+--------+------------+-------+---------------+------+---------+------+-------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
(gdb) p prebuilt->table->stat_n_rows
$3 = 65920
mysql> select * from mysql.innodb_table_stats;
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
| database_name | table_name | last_update | n_rows | clustered_index_size | sum_of_other_index_sizes |
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
...
| stattest | mytest | 2025-06-06 15:22:09 | 65920 | 161 | 97 |
...
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
统计数据内存和表同步
导入后,统计数据内存和表都是0
mysql> desc select count(*) from mytest ;
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | mytest | NULL | index | NULL | id | 5 | NULL | 1 | 100.00 | Using index |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
(gdb) p prebuilt->table->stat_n_rows
$4 = 0
mysql> select * from mysql.innodb_table_stats;
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
| database_name | table_name | last_update | n_rows | clustered_index_size | sum_of_other_index_sizes |
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
...
| stattest | mytest | 2025-06-06 07:00:06 | 0 | 1 | 1 |
...
四、bug和建议
从影响范围来看,影响还是比较广,因此需要注意一下,bug如下,
https://bugs.mysql.com/bug.php?id=98178
5.6 5.7 8.0 都存在问题,建议如下,A:避免使用--all-databases来导出数据,导出需要的数据库即可,避免这种情况。
B:导入数据后新库检查mysql.innodb_table_stats和mysql.innodb_index_stats表,如果没有大量的0,可以考虑重启一次数据库,启动后检查自动收集统计信息的参数innodb_stats_auto_recalc是否为ON。
C:如果出现类似问题倒完数据后,尽快全库收集统计数据,使用analyze table 即可。