首页 游戏 软件 资讯 排行榜 专题
首页
业界动态
MySQL 导入数据后导致 SQL 性能下降

MySQL 导入数据后导致 SQL 性能下降

热心网友
39
转载
2026-04-15

一、被关闭的自动统计数据收集

先来聊聊MySQL 8.0的统计信息机制。默认情况下,它启用了持久化统计(innodb_stats_persistent=ON)。这意味着表的行数、索引大小这些关键信息,不仅会放在内存里(比如table->stat_n_rows),还会被固化到mysql.innodb_table_statsmysql.innodb_index_stats这两张系统表中。正常情况下,内存和表里的数据是同步的:先改内存,再落盘;重启后,再用表里的数据来初始化内存。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

但这里有个暗坑:mysqldump操作可能会打破这种同步,甚至损坏系统表中的统计信息。

通常,当表的数据修改量超过当前统计行数的十分之一时,InnoDB会触发后台线程自动重新收集统计信息。然而,在特定场景下,MySQL会通过执行/*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */关闭这个自动收集功能。这样一来,导入数据时,无论插入多少行,都不会触发统计更新。

那么,什么场景会触发这个“关闭”操作呢?主要就两点:

  • 导出的数据库包含了mysql系统库。
  • 导出时使用了--all-databases参数(这是主要原因)。

因为--all-databases必然会包含存放统计信息的mysql.innodb_table_statsmysql.innodb_index_stats表。

MySQL源码中有一个名为is_innodb_stats_tables_included的函数,正是用来定义和判断这种行为的。为了验证,我们借助了一些代码分析工具,输入提示词:“请帮我找到is_innodb_stats_tables_included函数,并且分析其调用方式和作用”。结果很明确,如下图所示(在trae auto model模式下分析所得)。未来或许可以考虑用更智能的Agent来辅助代码分析,这也不失为一种高效的方法。

\

而问题的根源,恰恰就在这里。正是这个机制,导致了统计信息的丢失。我们接着往下分析。

二、统计信息丢失

统计信息丢失发生在两个层面:内存中的信息和持久化到表中的信息。它们双双“失灵”了。

第一,内存信息失效。虽然导入的SQL文件里包含了innodb_table_stats表的旧数据,但SQL语句执行时,优化器依赖的是table->stat_n_rows这个内存值。由于前面提到的自动收集功能被关闭了,这个内存值在数据导入过程中得不到更新。通过调试器(gdb)可以看到,prebuilt->table->stat_n_rows的值变成了0。

第二,持久化信息被覆盖。整个导入过程可以拆解为:先DROP TABLE,再CREATE TABLE,然后INSERT数据。问题出在CREATE TABLE这一步——它会覆盖innodb_table_stats表中对应表的现有记录。于是,持久化的统计信息在表刚重建完时就被清零了。紧接着,虽然插入了大量数据,但因为自动收集被关闭,系统不会去重新计算。最终结果就是:数据导完了,但innodb_table_stats表里却留下了大量值为0的记录,统计信息完全缺失。

三、测试

口说无凭,我们实际测试一下。分别在MySQL 8.0.23和8.0.41版本中进行,结果一致。重点关注测试库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 inset, 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 |...
+---------------+---------------+---------------------+--------+----------------------+--------------------------+

可以看到,内存值(65920)和持久化表中的值(65920)是同步的。

导入后,问题出现了:

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 inset, 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 |      ...

执行计划估算的行数变成了1(实际应为65920),内存统计值变成了0,持久化表中的n_rows也变成了0。统计信息彻底丢失了。

四、bug和建议

这个问题的潜在影响面其实挺广的,值得警惕。MySQL官方已将其确认为一个Bug,编号为:https://bugs.mysql.com/bug.php?id=98178。受影响的版本包括5.6、5.7和8.0系列。

那么,如何规避和解决呢?这里有几个建议:

A. 预防措施: 导出数据时,尽量避免使用--all-databases参数。只导出你真正需要的业务数据库,从根本上避免触发这个机制。

B. 事后检查: 数据导入新库后,务必检查mysql.innodb_table_statsmysql.innodb_index_stats这两张表。如果发现大量表的统计行数(n_rows)为0或异常小,可以考虑重启一次数据库实例。重启后,确认参数innodb_stats_auto_recalc是否为ON

C. 补救方案: 如果不幸已经中招,数据导入后出现了慢查询,最直接有效的办法就是立即手动触发全库的统计信息收集。执行命令:ANALYZE TABLE 表名; 对于受影响的表逐一处理,或者编写脚本批量处理。

来源:https://www.51cto.com/article/840211.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

mysql如何处理慢查询日志_配置long_query_time并分析结果
数据库
mysql如何处理慢查询日志_配置long_query_time并分析结果

MySQL慢查询日志配置与深度分析指南:精准定位性能瓶颈 MySQL慢查询日志是数据库性能调优的核心工具,能有效揭示SQL执行效率问题。然而,不当的配置和使用不仅无法提供有效信息,反而可能成为排查路上的“误导源”。掌握正确的开启、配置与分析方法,才能让慢查询日志真正发挥其“数据库听诊器”的作用,实现

热心网友
04.16
mysql如何配置日志保留天数_mysql expire_logs_days设置
数据库
mysql如何配置日志保留天数_mysql expire_logs_days设置

MySQL Binlog保留天数配置:从参数废弃到生产环境兜底方案 expire_logs_days 设置后不生效?先确认 MySQL 版本和启动方式 配置了binlog保留天数却看不到效果?问题的根源很可能在于MySQL版本。自 MySQL 5 7 6 版本起,expire_logs_days 参

热心网友
04.16
mysql怎么判断字段是否为Null_使用Is Null而非等号判断
数据库
mysql怎么判断字段是否为Null_使用Is Null而非等号判断

MySQL空值判断核心指南:为什么必须使用IS NULL而非= NULL? 在MySQL数据库操作中,有一个至关重要的原则:判断字段是否为空值时,必须使用 IS NULL 运算符,绝对禁止使用 = NULL 进行比较。 这并非简单的语法规定,而是由SQL标准中NULL值的特殊本质——“表示未知或不存

热心网友
04.16
mysql如何有效监控mysql锁状态_构建监控仪表盘建议
数据库
mysql如何有效监控mysql锁状态_构建监控仪表盘建议

MySQL锁监控实战:从被动排查到主动预警的完整方案 在数据库日常运维中,锁等待是导致性能突降的核心原因之一。然而,许多团队仍停留在问题发生后才翻查日志的被动响应模式。如何构建一套高效的MySQL锁监控体系,实现风险前置感知?关键在于选择合适的监控工具、准确解读锁现象,并建立可持续观测的核心指标。本

热心网友
04.16
mysql为什么会出现幻读现象_快照读与当前读在不同隔离级别的差异
数据库
mysql为什么会出现幻读现象_快照读与当前读在不同隔离级别的差异

MySQL幻读现象深度解析:MVCC机制未失效,关键在于区分“快照读”与“当前读” 当开发者遭遇MySQL幻读问题时,常会质疑可重复读(RR)隔离级别的有效性。实际上,问题根源往往并非MVCC机制失效,而在于开发者混淆了两种语义截然不同的数据读取方式——「快照读」与「当前读」,同时对InnoDB锁机

热心网友
04.16

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

如何查看实时行情K线图?币安交易所专业看盘工具使用指南
web3.0
如何查看实时行情K线图?币安交易所专业看盘工具使用指南

币安K线图深度解析:从入门到精通的实战看盘指南 在瞬息万变的加密资产市场,精准的行情分析是决策的基石。作为全球领先的交易平台,币安(Binance)不仅提供丰富的交易对,其内置的专业级K线图表工具更是每一位交易者洞察市场、捕捉机会的“利器”。无论是新手入门还是资深玩家优化策略,掌握币安实时行情K线图

热心网友
04.16
吉利i-HEV油电混动技术出炉 官方称“比日系有代际优势”
科技数码
吉利i-HEV油电混动技术出炉 官方称“比日系有代际优势”

吉利发布i-HEV智擎混动:以“电驱为主”理念,重新定义混动技术标准 4月13日,吉利汽车集团正式发布了其全新的混合动力技术——i-HEV智擎混动。这项技术交出了一份令人瞩目的成绩单:实测百公里综合油耗低至2 22L,发动机热效率高达48 41%,问鼎全球量产最高水平,并成为首个获得HEV车型1级能

热心网友
04.16
TES击败AL,Homme指教战队再度取胜Tabe BO5战绩红米7胜2负
游戏资讯
TES击败AL,Homme指教战队再度取胜Tabe BO5战绩红米7胜2负

TES击败AL,Homme执教战队再度取胜 LPL败者组的决赛落下帷幕,TES战队最终战胜了AL战队。这场对决,不仅是选手实力的比拼,某种程度上也是两位顶尖教练战术体系的又一次正面碰撞。 说起这两队的教练,那都是圈内公认的顶级人物。不过,从过往的交锋记录来看,一个有趣的现象逐渐清晰:Homme执教的

热心网友
04.16
燕云十六声清河话本迷案奇遇如何做-燕云十六声清河话本迷案奇遇的做法
游戏攻略
燕云十六声清河话本迷案奇遇如何做-燕云十六声清河话本迷案奇遇的做法

触发奇遇 想要在清河成功触发“话本迷案”奇遇?这需要一定的技巧与耐心。该奇遇并非随机出现,而是在您推进特定主线剧情或完成某些日常任务后,才有几率解锁。因此,保持较高的游戏活跃度至关重要——建议您多探索清河的不同区域,主动与各类NPC对话,触发奇遇的概率将显著提升。请记住,您的探索越深入、越细致,惊喜

热心网友
04.16
《风启之旅》爆火玩家在线超10万 官方招募玩家高手解决多人服务问题
游戏资讯
《风启之旅》爆火玩家在线超10万 官方招募玩家高手解决多人服务问题

《风启之旅》爆火玩家在线超10万 官方招募玩家高手解决多人服务问题 生存冒险游戏《风启之旅》(Windrose)最近的势头,可真有点“出道即巅峰”的意思。游戏刚刚开启抢先体验,就迅速收获好评并火爆出圈,同时在线玩家数一举突破了10万大关。然而,这人气来得太猛,也给开发团队带来了一个甜蜜的烦恼——多人

热心网友
04.16