直方图仅在无可用索引或未命中索引前导列、列值分布严重倾斜、且用于WHERE/JON/GROUP BY选择率估算时,才影响优化器对索引使用和驱动表的决策;否则优先采用索引统计信息。

直方图本身不改变索引选择,它只影响优化器对“要不要用索引”“用哪个表做驱动表”的判断——前提是该列没索引,或查询条件没命中索引前导列。
什么时候直方图能真正影响索引使用决策
优化器是否参考直方图,取决于三个硬性条件同时满足:
- 目标列上没有可用索引,或虽有索引但查询条件未命中前导列(例如复合索引
(status, created_at),却只查WHERE created_at > '2026-01-01') - 该列值分布严重倾斜(比如
status中'pending'占 95%,'done'和'failed'各占 2.5%) - 该列出现在
WHERE、JOIN或GROUP BY条件中,且优化器需要估算选择率来决定是否走全表扫描、用哪个表做驱动表
如果列上有索引且查询能走索引,优化器优先用索引统计信息,HISTOGRAM 不会被读取——这点常被误认为“直方图没生效”。
ANALYZE TABLE UPDATE HISTOGRAM 的写法陷阱
语法看着简单,参数错一个就白跑:
- 必须显式指定桶数:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 25 BUCKETS;。省略WITH N BUCKETS会用默认 100,小表浪费资源,大表桶太少失真 - 多列要重复写:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 25 BUCKETS, UPDATE HISTOGRAM ON priority WITH 16 BUCKETS;——不能写成ON status, priority - 执行需
SELECT和INSERT权限;若启用了innodb_read_only=ON,会直接报错ERROR 1290 (HY000) - 执行期间持表级只读锁,长事务未结束时会被阻塞,务必避开业务高峰
怎么验证直方图被实际用了
别只看语句执行成功,得对比执行计划里的预估行数变化:
- 先跑一次
EXPLAIN SELECT ... WHERE column > X,记下rows和filtered值(比如filtered: 33.33是默认估算) - 建完直方图后重跑同一语句,如果
filtered变成接近真实比例的值(比如真实占比 2.4%,显示filtered: 2.40),说明优化器采纳了直方图 - 注意:如果加了直方图后
EXPLAIN显示仍走全表扫描,但filtered值变准了,说明它在帮优化器选连接顺序,而不是改单表访问路径
删掉过期直方图比留着更安全
直方图不会自动更新,数据分布一变,旧直方图就是误导源:
- 当列值分布发生根本变化(如原
status从 95%pending变成各状态均分),旧直方图会让优化器误判连接顺序或执行路径 - 删除命令是:
ANALYZE TABLE orders DROP HISTOGRAM ON status; - 定期检查
mysql.column_stats表中的last_updated字段,结合业务变更节奏决定是否重建
最易被忽略的一点:直方图不是“补丁”,它只在索引失效场景下起作用;想靠它绕过索引设计缺陷,反而会让问题更隐蔽。


















