如何处理MySQL 5.7执行计划频繁变动问题_固定索引统计信息采样页数

风雪君_2951

风雪君_2951

2026-05-10

1121人浏览

原创

innodb_stats_persistent_sample_pages调低反而让执行计划更稳是错误认知;实际是默认值20在数据倾斜时易致基数估算失真,引发索引误判或全表扫描,应根据数据分布适度调高至100~200并配合analyze table,mysql 8.0起优先用直方图替代。

如何处理mysql 5.7执行计划频繁变动问题_固定索引统计信息采样页数

为什么innodb_stats_persistent_sample_pages调低反而让执行计划更稳

MySQL 5.7 默认 innodb_stats_persistent_sample_pages = 20,但这个值在数据分布不均(比如某索引前10%值占了90%行)时,采样页太少会导致基数(Cardinality)估算严重失真。优化器一看“这个索引选择性很差”,就跳过它,转而全表扫描——哪怕你加了索引也白搭。

实操建议:

  • 先查真实倾斜程度:SELECT COUNT(DISTINCT col) / COUNT(*) FROM table_name,若结果
  • 把采样页数提高到 100 或 200(上限默认是 2000),命令:SET GLOBAL innodb_stats_persistent_sample_pages = 200;
  • 必须配合 ANALYZE TABLE 才生效,只改参数不刷新统计信息毫无作用
  • 注意:该变量仅对启用了 innodb_stats_persistent = ON 的表有效(5.7 默认开启)

执行计划变来变去,ANALYZE TABLE 后还是不准怎么办

不是所有表都适合用默认采样策略。尤其当表里有大量 NULL、空字符串、或 JSON 字段(5.7 中 JSON 的 CARDINALITY 计算本身就不准),ANALYZE TABLE 可能反复给出矛盾结果。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载

这时要人工干预:

  • 禁用自动重采样:SET GLOBAL innodb_stats_auto_recalc = OFF;,防止写入触发不可控更新
  • 用 FORCE 强制指定采样页数:ANALYZE TABLE t1 PERSISTENT FOR ALL;(需先设好 innodb_stats_persistent_sample_pages)
  • 对关键索引单独验证:SHOW INDEX FROM t1; 对比 Cardinality 和 SELECT COUNT(DISTINCT idx_col) FROM t1,差10倍以上就得调参重刷
  • 避免在业务高峰跑 ANALYZE TABLE,它会读取聚簇索引页,可能引发短暂锁等待

optimizer_switch 里哪些开关会影响执行计划稳定性

5.7 的 optimizer_switch 默认开启一堆规则,其中几个和执行计划抖动强相关:

  • condition_fanout_filter=on:启用后优化器会预估条件过滤率,但对复杂 IN 或 OR 表达式容易误判——关掉它常能让 EXPLAIN 更可预测
  • derived_merge=on:子查询合并可能改变访问路径,尤其当子查询含 LIMIT 或 GROUP BY;临时关掉可快速验证是否由此引发波动
  • index_condition_pushdown=on:一般有益,但在某些复合索引+范围查询组合下,反而让优化器放弃使用索引;可对比开/关时的 key_len 和 rows
  • 修改方式:SET GLOBAL optimizer_switch='condition_fanout_filter=off,derived_merge=off';,别直接覆盖整个值

为什么加了索引、ANALYZE TABLE 也做了,EXPLAIN 还是选错索引

执行计划“选错”不一定是统计信息问题,5.7 存在几个隐蔽但高频的干扰点:

  • SQL_NO_CACHE 不影响执行计划,但会让 EXPLAIN 结果看起来“不稳定”——其实是缓存层掩盖了真实执行路径,务必在关闭查询缓存下测试
  • 隐式类型转换:比如 WHERE varchar_col = 123,会导致索引失效且优化器误判成本;检查 EXPLAIN 的 type 是否为 ALL 或 range 突然变 ref
  • 分区表的统计信息是按分区单独维护的,ANALYZE TABLE 只刷新主表元数据,得用 ANALYZE TABLE t1 PARTITION(p0); 逐个刷
  • 如果用了 FORCE INDEX 但执行计划仍漂移,大概率是 MySQL 在 prepare 阶段缓存了错误计划——执行 FLUSH TABLES 清除语句缓存
执行计划频繁变动的本质,是优化器在用不完整的数据做决策。统计信息只是入口,真正要稳住,得同时控制采样质量、关闭干扰开关、排除隐式转换——三者缺一不可。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4403

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

931

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1149

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6361

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3163

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6320

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8621

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1170

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1032

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 188人学习