這個問題是線上遇到的問題,BUG有關(guān),遇到后可能導致SQL運行緩慢,導致大量的慢查詢,進而影響線上業(yè)務,還是需要警惕。
一、被關(guān)閉的自動統(tǒng)計數(shù)據(jù)收集
首先MySQL 8.0默認全部使用persist統(tǒng)計數(shù)據(jù)(innodb_stats_persistent=ON),統(tǒng)計數(shù)據(jù)放到mysql.innodb_table_stats和mysql.innodb_index_stats表中,內(nèi)存中使用table->stat_n_rows等信息表示,正常情況下是先改內(nèi)存,在寫入表中,重啟后會使用表的信息初始化內(nèi)存信息,
一般情況下是同步的。但是mysqldump可能導致信息不同步,并且損壞mysql.innodb_table_stats和mysql.innodb_index_stats表中的信息。
一般情況下,如果修改量超過當前統(tǒng)計數(shù)據(jù)行數(shù)的1/10,則需要收集統(tǒng)計數(shù)據(jù),會推給后臺收集線程進行統(tǒng)計數(shù)據(jù)收集。
但是在以下的情況下會使用/*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */ 關(guān)閉自動統(tǒng)計數(shù)據(jù)的收集,也就是導入的時候插入數(shù)據(jù)不觸發(fā)自動統(tǒng)計數(shù)據(jù)收集,
- 導出database包含mysql庫
- 導出使用--all-databases(主要)
- 導出包含mysql.innodb_table_stats和mysql.innodb_index_stats表
這個函數(shù)為is_innodb_stats_tables_included,定義了這種行為,并且用trae分析了一下也得到了同樣的結(jié)果,如下,


而就是這個原因?qū)е铝私y(tǒng)計數(shù)據(jù)的丟失,我們繼續(xù)分析。
二、統(tǒng)計信息丟失
這里存在2個問題點如下,包含統(tǒng)計數(shù)據(jù)的內(nèi)存信息和持久化表,
1、 雖然導入的時候會導入innodb_table_stats表,但是語句執(zhí)行的時候使用的是table->stat_n_rows的內(nèi)存信息,因為前面說的自動統(tǒng)計數(shù)據(jù)收集已經(jīng)關(guān)閉,因此無法得到更改,
(gdb) p prebuilt->table->stat_n_rows
$4 = 0
2、雖然導入的時候會導入innodb_table_stats表,然后執(zhí)行drop table/create table,接著insert 數(shù)據(jù),但是持久化的信息也會被create table 覆蓋掉innodb_table_stats中的信息,因此innodb_table_stats表中的統(tǒng)計信息會為0,而insert 數(shù)據(jù)由于關(guān)閉了自動統(tǒng)計數(shù)據(jù)收集,因此不會自動收集統(tǒng)計數(shù)據(jù),這樣導致數(shù)據(jù)導入完成后innodb_table_stats中大量的0,也就是沒有統(tǒng)計信息。
三、測試
這里使用8023進行測試,同時測試8041都是一樣的結(jié)果,注意持久化統(tǒng)計數(shù)據(jù)中mytest的統(tǒng)計信息。
導入前
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 |
...
+---------------+---------------+---------------------+--------+----------------------+--------------------------+
統(tǒng)計數(shù)據(jù)內(nèi)存和表同步
導入后,統(tǒng)計數(shù)據(jù)內(nèi)存和表都是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來導出數(shù)據(jù),導出需要的數(shù)據(jù)庫即可,避免這種情況。
B:導入數(shù)據(jù)后新庫檢查mysql.innodb_table_stats和mysql.innodb_index_stats表,如果沒有大量的0,可以考慮重啟一次數(shù)據(jù)庫,啟動后檢查自動收集統(tǒng)計信息的參數(shù)innodb_stats_auto_recalc是否為ON。
C:如果出現(xiàn)類似問題倒完數(shù)據(jù)后,盡快全庫收集統(tǒng)計數(shù)據(jù),使用analyze table 即可。