MySQL Histogram 统计信息过期会怎样影响执行计划
来源:17golang原创
时间:2026-10-09 00:45:43 145浏览 收藏
会。MySQL Histogram 不是随表数据自动逐行维护的索引结构,而是优化器保存的一份列值分布统计。大量导入、批量删除或业务分布突变后,如果 Histogram 仍代表旧分布,优化器可能把过滤率估错,进而在索引、全表扫描、连接顺序或访问代价之间做出不合适的选择。先查 last-updated 和 EXPLAIN,再用 ANALYZE TABLE 更新,比直接加索引更稳妥。
官方文档:https://dev.mysql.com/doc/refman/8.4/en/optimizer-statistics.html
- Histogram 主要帮助优化器估算列值比较的选择性,尤其适合没有索引的列;索引范围估算可能优先使用其他机制。
- 统计信息按需生成,数据变更后会逐渐过期;过期不一定报错,却可能让 rows、filtered 和访问路径失真。
- 处理顺序是查看元数据、对照 EXPLAIN、用 ANALYZE TABLE 重建,再决定保留、删除或临时禁用。
Histogram 过期影响的本质是“估算错了”
Histogram 以 buckets 描述列值分布,元数据位于 INFORMATION_SCHEMA.COLUMN_STATISTICS 视图中。它包含 last-updated、采样率、桶数量和直方图类型等信息。优化器会把这些分布用于常量比较的选择性估算,例如 =、范围、IN 和 IS NULL。
这里的“过期”不是一个固定天数阈值,而是统计分布与当前数据不再相符。比如状态列原本只有少量异常值,批量回填后异常值变成主流;Histogram 仍按旧比例估算,就可能低估或高估候选行。EXPLAIN 中的 rows、filtered、访问类型和连接顺序,都是定位线索,但不能只看一个字段就下结论。

先查更新时间,再把估算与真实现象对照
可以先查看目标表和列的 Histogram 元数据。下面只读取统计视图,不会修改数据;SQL 注释说明每个字段的诊断用途。
-- 读取目标列的直方图元数据,先判断分布统计是否明显落后
SELECT TABLE_SCHEMA,
TABLE_NAME,
COLUMN_NAME,
HISTOGRAM->>'$."last-updated"' AS last_updated,
HISTOGRAM->>'$."sampling-rate"' AS sampling_rate,
HISTOGRAM->>'$."histogram-type"' AS histogram_type,
JSON_LENGTH(HISTOGRAM->>'$."buckets"') AS bucket_count
FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
WHERE TABLE_SCHEMA = 'app'
AND TABLE_NAME = 'orders'
AND COLUMN_NAME = 'status';
再对同一条慢查询执行 EXPLAIN,把计划中的估算行数与业务已知的结果规模、慢查询耗时或抽样统计对照。若只有某个常量范围在数据分布突变后变慢,且估算与实际差距明显,Histogram 过期就值得优先排查;若列已有高选择性索引,还要考虑 range optimizer 或 index dive 是否已经提供更合适的估算。
用 ANALYZE TABLE 重建,并用 EXPLAIN 验证
确认分布确实变化后,只更新相关列的 Histogram,避免把无关表的统计维护混在一起。bucket 数量应结合列的基数和估算稳定性调整,不要把“桶越多越好”当成结论。
-- 只重建 status 列的直方图,避免无关列产生额外统计变更 ANALYZE TABLE app.orders UPDATE HISTOGRAM ON status WITH 128 BUCKETS; -- 重建后重新查看计划,确认 rows、filtered 与访问路径是否更接近业务事实 EXPLAIN SELECT order_id FROM app.orders WHERE status = 'delayed';
验证重点不是“计划发生了变化”,而是变化后是否更贴近当前分布、延迟是否改善,以及是否影响了其他查询。最好保留更新前后的 EXPLAIN 文本和代表性参数;如果变更涉及高峰流量,先在影子环境或低峰窗口验证。

哪些情况不该盲目更新 Histogram
| 现象 | 优先检查 | 处理倾向 |
|---|---|---|
| 非索引列分布明显变化 | last-updated、桶分布、EXPLAIN filtered | 更新目标列 Histogram |
| 索引范围查询估算已稳定 | range optimizer、index dive、索引基数 | 先比较,不强行增加 Histogram |
| 更新后计划反而变差 | 更新前后计划、参数分布、采样率 | 回滚统计变更或删除 Histogram |
| 需要临时隔离影响 | 会话级 optimizer_switch | 谨慎关闭 condition_fanout_filter |
MySQL 文档明确提示,统计信息过期时 Histogram 可能不再改善执行;可以重新执行 ANALYZE TABLE,也可以删除 Histogram。临时关闭 condition_fanout_filter 会连带影响其他优化,因此更适合定位问题或短时止血,不宜当成永久配置。
-- 仅在定位阶段临时关闭相关过滤率优化,结束后恢复会话设置 SET SESSION optimizer_switch = 'condition_fanout_filter=off'; -- 明确删除不再适合当前分布的列直方图,交由其他估算机制工作 ANALYZE TABLE app.orders DROP HISTOGRAM ON status;
相关问题
Histogram 过期会直接让 MySQL 报错吗?
通常不会。它更常见的表现是估算行数、过滤率或访问路径变得不准确,最终体现为性能波动。
有索引的列还需要 Histogram 吗?
不一定。优化器可能优先使用范围估算或 index dive;应通过 EXPLAIN 和实际分布比较,而不是按列是否有索引一刀切。
更新 Histogram 后执行计划变了就是成功吗?
不是。计划变化只是信号,仍要检查代表性参数下的耗时、扫描量和并发影响,确认新估算更接近当前数据。
-
374 收藏
-
499 收藏
-
384 收藏
-
184 收藏
-
265 收藏
-
422 收藏
-
480 收藏
-
222 收藏
-
160 收藏
-
337 收藏
-
420 收藏
-
153 收藏
-
313 收藏
-
351 收藏
-
112 收藏
-
127 收藏
-
291 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习