MySQL优化器统计信息的配置指南

 更新时间:2025年09月30日 09:34:28   作者:lang20150928  
在 MySQL 中,查询优化器(Query Optimizer) 负责决定执行 SQL 语句的最佳方式,比如是否使用某个索引、用哪个索引、是否进行全表扫描等,本文给大家介绍了MySQL优化器统计信息的配置指南,需要的朋友可以参考下

这段内容出自 MySQL 官方文档,主题是 “配置非持久性优化器统计信息参数”(Non-Persistent Optimizer Statistics Parameters),属于 InnoDB 存储引擎的性能调优部分。下面我将逐段为你详细解释这段内容的含义,并用通俗易懂的语言帮助你理解其背后的原理和实际影响。

核心概念:什么是“优化器统计信息”?

在 MySQL 中,查询优化器(Query Optimizer) 负责决定执行 SQL 语句的最佳方式,比如是否使用某个索引、用哪个索引、是否进行全表扫描等。

为了做出这些决策,优化器需要知道一些关于表和索引的数据分布情况,例如:

  • 一张表有多少行?
  • 某个索引有多少不同的值?(即“基数”,Cardinality)
  • 索引的选择性如何?

这些数据被称为 “优化器统计信息”(Optimizer Statistics)

什么是“非持久性”统计信息?

MySQL 提供两种方式来存储这些统计信息:

类型是否保存到磁盘特点
持久性(Persistent)✅ 是统计信息写入磁盘,重启后不丢失
非持久性(Non-Persistent)❌ 否统计信息只存在内存中,重启后丢失

默认情况下,innodb_stats_persistent = ON,也就是启用持久性统计信息。

但如果你设置:

SET GLOBAL innodb_stats_persistent = OFF;

或者在创建/修改表时指定:

CREATE TABLE t (...) STATS_PERSISTENT=0;
ALTER TABLE t STATS_PERSISTENT=0;

那么这张表的统计信息就是 非持久性的 —— 只存在内存中,MySQL 重启后就会丢失,下次启动时需要重新采样生成。

非持久性统计信息何时更新?

当统计信息是非持久性时,它们会在以下几种情况下被自动更新(重新计算):

1. 执行 ANALYZE TABLE

ANALYZE TABLE my_table;

这是最直接的方式,手动触发统计信息更新。

2. 查询元数据(如 SHOW TABLE STATUS, SHOW INDEX) + 开启了 innodb_stats_on_metadata=ON

默认这个选项是 OFF,但如果开启:

SET GLOBAL innodb_stats_on_metadata = ON;

那么每次执行:

  • SHOW TABLE STATUS
  • SHOW INDEX
  • 查询 information_schema.TABLESSTATISTICS

都会导致 InnoDB 重新统计表的索引信息!

注意:这可能导致性能问题!

  • 如果你的库有很多表或索引,这类操作会变慢。
  • 执行计划可能不稳定(因为每次查元数据都可能改变统计值,进而改变执行计划)。

所以建议:生产环境不要开启 innodb_stats_on_metadata

3. 使用 mysql 客户端并启用 --auto-rehash(默认行为)

当你运行:

mysql -u user -p

默认启用了 --auto-rehash,它支持命令行自动补全数据库名、表名、列名。

但它的工作原理是:打开所有 InnoDB 表 → 触发统计信息更新!

后果:客户端启动变慢,尤其在大库上。

解决办法:关闭 auto-rehash

mysql --disable-auto-rehash -u user -p

4. 第一次打开一张表

当某张表第一次被访问(打开)时,InnoDB 会检查是否需要更新统计信息。

5. 表数据变化超过阈值(1/16 ≈ 6.25%)

如果自上次统计以来,表中有 超过 1/16 的数据被修改(插入、删除、更新),InnoDB 会认为统计信息过期,下次打开表时自动重新采样更新。

这是一个启发式规则,防止执行计划基于过时的统计信息做出错误选择。

如何控制统计信息的准确性?—— innodb_stats_transient_sample_pages

由于统计信息是通过 采样 得来的(称为 random dives:随机读取若干页),所以它的准确性取决于采样量。

参数说明:

  • 参数名innodb_stats_transient_sample_pages
  • 作用范围:全局(GLOBAL)
  • 适用场景:仅当 innodb_stats_persistent = OFF 时有效(非持久性统计)
  • 默认值:8 页
  • 可调范围:一般建议 8~100,太高会影响性能

工作原理:

InnoDB 从每个索引中随机抽取若干个数据页,分析其中的键值分布,估算出索引的“基数”(Cardinality)。

比如:

  • 主键索引:每页都抽一点,估算总行数。
  • 普通索引:看有多少不同值,判断选择性。

设置方法:

SET GLOBAL innodb_stats_transient_sample_pages = 20;

调整采样页数的影响

设置值优点缺点
太小(如 1~2)快,I/O 少统计极不准,可能导致优化器选错索引,引发全表扫描
适中(如 8~20)平衡速度与精度大表可能仍不够准
太大(如 100+)更准确每次更新统计信息都要读很多页 → 打开表变慢,SHOW TABLE STATUS 变卡

特别提醒:

  • 大表或频繁用于 JOIN 的表,8 页采样很可能不够!
  • 不准确的统计 → 优化器误判索引有效性 → 导致 全表扫描(Full Table Scan) → 性能急剧下降。

最佳实践建议

优先使用持久性统计信息

SET GLOBAL innodb_stats_persistent = ON; -- 默认已开启

这样统计信息保存在磁盘上,重启不失效,更稳定。

避免频繁触发统计更新

关闭 innodb_stats_on_metadata

SET GLOBAL innodb_stats_on_metadata = OFF;
  • 客户端连接时加 --disable-auto-rehash,提升连接速度。

合理设置采样页数

  • 如果你确实使用非持久性统计(如旧版本 MySQL),且有大量大表:
    SET GLOBAL innodb_stats_transient_sample_pages = 32; -- 或 64
    
  • 测试不同值对统计准确性和性能的影响,找到平衡点。

定期执行 ANALYZE TABLE
尤其是在大批量导入/删除数据之后,手动更新统计信息,确保执行计划最优。

不要临时调大 sample_pages → 执行 ANALYZE → 再调小
因为统计信息会在多种场景下自动更新(不只是 ANALYZE),这样做没有意义,反而增加复杂度。

根据表大小调整策略

  • 小表:8 页足够
  • 大表:建议提高采样页数(如 32~64)
  • 混合型数据库:折中取值(如 20~32)

总结:一句话理解全文

当 MySQL 的 InnoDB 表使用非持久性统计信息时,统计结果只存在内存中,重启丢失;系统会在特定操作(如 ANALYZE TABLE、打开表、数据变更过多等)时自动重新采样;采样的准确度由 innodb_stats_transient_sample_pages 控制——太小不准,太大影响性能,应根据表的大小和业务需求权衡设置。

附加:常见问题解答

Q: 我应该用持久性还是非持久性统计?
A: 推荐持久性(默认)。更稳定,适合生产环境。非持久性主要用于兼容老版本或特殊调试。

Q: 为什么我的 SHOW TABLE STATUS 很慢?
A: 可能是开启了 innodb_stats_on_metadata=ON,导致每次都要重新统计。关闭它即可。

Q: 统计信息不准会导致什么后果?
 A: 查询优化器可能选择错误的执行计划,比如该用索引却做了全表扫描,导致查询极慢。

Q: 多久更新一次统计信息?
A: 自动机制:当数据变更超过约 6.25% 时,下次访问表会触发更新。也可以手动 ANALYZE TABLE

如果你提供具体的 MySQL 版本和业务场景(比如有没有大表、是否频繁导入数据),我可以给出更精确的配置建议。

以上就是MySQL优化器统计信息的配置指南的详细内容,更多关于MySQL优化器统计信息配置的资料请关注脚本之家其它相关文章!

相关文章

  • Windows XP系统安装MySQL5.5.28图解教程

    Windows XP系统安装MySQL5.5.28图解教程

    很多朋友在winxp系统中开发php等,需要安装mysql数据库,这里简单介绍下,如何在xp下安装mysql软件,其实跟其它系统都差不多,主要是软件对系统的兼容性
    2013-05-05
  • MySQL索引优化的实际案例分析

    MySQL索引优化的实际案例分析

    这篇文章主要介绍了MySQL索引优化的一些实际案例,主要是用到Order by desc/asc limit M的方法,需要的朋友可以参考下
    2015-05-05
  • mysql按照时间分组查询的语句

    mysql按照时间分组查询的语句

    这篇文章主要介绍了mysql按照时间分组查询的语句,非常实用,sql语句简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • Mysql迁移Postgresql的实现示例

    Mysql迁移Postgresql的实现示例

    本文主要介绍了Mysql迁移Postgresql的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • mysql二进制日志文件恢复数据库

    mysql二进制日志文件恢复数据库

    喜欢的在服务器或者数据库上直接操作的兄弟们你值得收藏下!不然你就悲剧了。-----(当然我也是在网上搜索的资料!不过自己测试通过了的!)
    2014-08-08
  • MySQL避免插入重复记录的方法

    MySQL避免插入重复记录的方法

    这篇文章主要介绍了MySQL避免插入重复记录的方法,需要的朋友可以参考下
    2023-10-10
  • 如何安装MySQL Community Server 5.6.39

    如何安装MySQL Community Server 5.6.39

    这篇文章主要为大家详细介绍了MySQL Community Server 5.6.39安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • mysql8.0.23 msi安装超详细教程

    mysql8.0.23 msi安装超详细教程

    这篇文章主要介绍了mysql8.0.23 msi安装超详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • mysql查询语句join、on、where的执行顺序

    mysql查询语句join、on、where的执行顺序

    这篇文章主要介绍了mysql查询语句join、on、where的执行顺序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • MySQL 元数据的使用小结

    MySQL 元数据的使用小结

    本文主要介绍了MySQL 元数据的使用,通过INFORMATION_SCHEMA数据库访问,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2025-08-08

最新评论