登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

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、访问类型和连接顺序,都是定位线索,但不能只看一个字段就下结论。

MySQL COLUMN_STATISTICS 中 Histogram buckets 影响 rows 和 filtered 估算的静态关系说明图
图1:结构说明图,展示列值分布、Histogram 桶、过滤率估算与执行计划的关系,不是 MySQL 截图或运行证据。

先查更新时间,再把估算与真实现象对照

可以先查看目标表和列的 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 文本和代表性参数;如果变更涉及高峰流量,先在影子环境或低峰窗口验证。

MySQL ANALYZE TABLE 更新 Histogram 后使用 EXPLAIN 对照并决定保留或删除的静态边界图
图2:关系说明图,展示 Histogram 重建、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 后执行计划变了就是成功吗?

不是。计划变化只是信号,仍要检查代表性参数下的耗时、扫描量和并发影响,确认新估算更接近当前数据。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>