能,直方图仅在基数估算时影响执行计划预估行数,从而可能优化连接顺序或访问路径;它不改变索引、不重写sql、不自动建索引,且需显式创建与验证。

直方图在 MySQL 8.0 中真能改善非均匀数据的执行计划?
能,但仅限于优化器做基数估算(cardinality estimation)时参考——它不改变索引、不重写 SQL、也不触发自动索引创建。MySQL 8.0 的直方图是内存中构建的采样统计,只影响 EXPLAIN 输出里的 rows 预估值,进而可能让优化器避开错误的连接顺序或访问路径。前提是:列上没有可用索引,或优化器因低估/高估导致选错 range 扫描 vs ref 查找。
什么时候该建直方图?看这三点再动手
别一上来就给所有大表列加直方图。重点覆盖以下场景:
- 列值分布严重倾斜(比如
status字段:95% 是'active',3%'pending',其余分散在 10+ 状态) - 该列出现在
WHERE条件中但无索引,或有索引但优化器因统计过期仍走全表扫描 -
EXPLAIN显示预估行数和实际相差 10 倍以上(例如预估 1 行,实际扫描 5 万行)
注意:ANALYZE TABLE 不会自动收集直方图;必须显式用 ANALYZE TABLE ... UPDATE HISTOGRAM。
UPDATE HISTOGRAM 的参数怎么选才不翻车
关键参数是 BUCKETS 和 DATA_TYPE(隐式推导),但最容易出问题的是桶数设置:
- 默认
BUCKETS = 100,对大多数文本/枚举列够用;但对高基数值列(如用户 ID、时间戳),100 桶会把大量不同值挤进同一桶,失去区分度 - 超过 1000 桶不推荐:MySQL 会显著增加
information_schema.COLUMN_STATISTICS表体积,且解析开销上升,SELECT执行前需额外加载直方图元数据 - 字符串列若启用了
utf8mb4且平均长度 > 200 字节,直方图构建可能失败并报错ER_TOO_LONG_STRING,此时应先用SUBSTRING()截断再建(但会损失精度)
示例:给订单状态建 25 桶直方图(足够覆盖常见状态)
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 25 BUCKETS;
直方图生效但查询没变快?检查这三个盲区
直方图只是调优链条中的一环,以下情况会让它的作用归零:
- 查询中用了函数包裹列,如
WHERE UPPER(status) = 'ACTIVE'—— 直方图基于原始列值,无法参与估算 - 使用了分区表且查询条件未命中具体分区,优化器可能忽略直方图(MySQL 8.0.19+ 修复部分情况,但仍有边界)
- 直方图建在从库上,但主库没同步
information_schema.COLUMN_STATISTICS(该表不复制),导致从库EXPLAIN和主库行为不一致
验证是否生效:查 information_schema.COLUMN_STATISTICS 看 HISTOGRAM 字段是否为非空 JSON;再对比加直方图前后 EXPLAIN FORMAT=JSON 中 "rows_estimation" 节点的变化。
直方图不是银弹,它只修正“有多少行匹配”这个单一估算点。如果瓶颈在锁等待、磁盘 I/O 或网络传输,它完全无感。











