直方图仅在无索引(或未命中复合索引前导列)、数据严重倾斜、且列直接用于where/join/group by时,提升优化器选择率估算精度;它不改变执行计划的物理访问方式,也不弥补缺失索引。

直方图不能“弥补”无索引字段的缺失,它只让优化器对这类字段的选择率估算更准——前提是字段真没索引、查询条件裸用列名、且数据分布严重倾斜。盲目建直方图反而可能误导优化器选错连接顺序或物化策略。
直方图生效的三个硬性前提
它不是开关一开就起效,必须同时满足:
- 目标列上 没有可用索引,或虽有复合索引但查询未命中前导列(例如索引是
(status, created_at),却只写WHERE created_at > '2025-01-01') - 该列值分布严重不均(比如
status中'pending'占 92%,'failed'仅占 0.3%) - 该列直接出现在
WHERE、JOIN或GROUP BY条件中,且优化器需要估算选择率来决定是否全表扫描、选哪个表当驱动表
ANALYZE TABLE UPDATE HISTOGRAM 的实操要点
语法看着简单,参数错一个就白跑:
- 必须显式指定桶数:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 25 BUCKETS;—— 省略WITH N BUCKETS会默认用 100,小表浪费资源,大表桶太少失真 - 多列要重复写
UPDATE HISTOGRAM ON: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) - 执行期间持表级只读锁,长事务未结束时会被阻塞,务必避开业务高峰
怎么确认直方图真的被优化器用了?
别只看 Query OK,得验证两处:
- 查元数据是否存在:
SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME = 'orders' AND COLUMN_NAME = 'status';—— 返回非空 JSON 才算写入成功 - 对比执行计划变化:对低频值执行
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE status = 'failed';,观察query_block->condition_filtering_probability是否明显下降(如从0.01→0.0003),同时rows预估是否更接近真实扫描行数 - 注意陷阱:如果该列上有索引,哪怕只是辅助索引,优化器大概率忽略直方图;
WHERE UPPER(status) = 'FAILED'这类函数包裹也会让直方图失效
最常被忽略的一点:直方图不会让 type: ALL 变成 type: ref,它只影响 rows 预估和后续连接顺序、物化决策等二级判断。如果你的查询本该走索引却没走,先检查索引设计和条件写法,而不是急着加直方图。











