直方图仅在列值分布倾斜、无可用索引、且该列用于WHERE/JON/GROUP BY条件时才生效;需严格满足三硬性条件,否则无效。

直方图不会让复杂SQL“自动走对路径”,它只在优化器对某列的选择率估算严重失准时,且该列又没索引可用时,才可能扳正执行计划——否则建了也白建。
直方图真正起效的三个硬性条件
别急着跑 ANALYZE TABLE,先确认这三点是否同时满足:
- 目标列出现在
WHERE、JON或GROUP BY条件中(注意:不是ORDER BY或函数包裹列,如UPPER(col)) - 该列上没有可用索引,或虽有复合索引但查询未命中前导列(例如索引是
(status, created_at),却只写WHERE created_at > '2025-01-01') - 列值分布明显倾斜(比如
status中'active'占 94%,其余 8 种状态加起来才 6%)
缺一不可。只要有一条不成立,EXPLAIN 中的 rows 和 filtered 就不会变,直方图等于没被读取。
SINGLETON 与 EQ_HEIGHT 类型怎么选
选错类型比不建还危险:要么精度崩塌,要么解析变慢甚至拖垮元数据表。
- 低基数离散值(如状态、类型、布尔字段)→ 必须用
SINGLETON,桶数设为唯一值数量 ±20%。例如 12 种订单状态,就写WITH 14 BUCKETS - 高基数连续值(如
created_at、user_id、金额)→ 用EQ_HEIGHT,桶数严格控制在 100–256;超过 1000 会显著拉长查询解析时间,且information_schema.COLUMN_STATISTICS表体积暴涨 - 不写
TYPE参数时默认EQ_HEIGHT,对枚举列大概率误判,导致频次信息全丢
字符串列若平均长度 > 200 字节,直接建可能报 ER_TOO_LONG_STRING;可临时截断:ANALYZE TABLE t UPDATE HISTOGRAM ON SUBSTRING(status, 1, 100) WITH 20 BUCKETS,但要注意精度损失。
建完必须验证,不能只看语句是否成功
ANALYZE TABLE t UPDATE HISTOGRAM ON col; 执行成功 ≠ 优化器用了它。验证分两步:
- 查元数据是否存在:
SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME = 't' AND COLUMN_NAME = 'col';—— 返回非空 JSON 才算写入成功 - 比对
EXPLAIN FORMAT=JSON的预估变化:建前后分别执行EXPLAIN FORMAT=JSON SELECT * FROM t WHERE col = 'x';,重点看"rows"字段是否从 12000 明显降到 380 这类量级变化
如果 filtered 值仍是默认的 10.00(等值查询)、33.33(范围查询),说明直方图没被采纳——大概率是条件写了函数、索引干扰、或根本没满足那三个硬条件。
直方图不是长期有效的“设置一次就完事”
数据持续写入后,直方图会过期。尤其在高频更新的状态类字段上,一周不更新就可能误导优化器。但也不能天天跑 ANALYZE TABLE,它会持表级只读锁,长事务未结束时会被阻塞。建议:
- 在业务低峰期手动触发,避开高峰时段
- 对变更频繁的列,配合监控(如对比
INFORMATION_SCHEMA.COLUMN_STATISTICS.last_updated与业务更新节奏)决定更新周期 - 删掉不再需要的直方图:
ANALYZE TABLE t DROP HISTOGRAM ON col;,避免冗余统计干扰优化器判断
最常被忽略的一点:直方图只影响选择率估算,它不改变索引结构、不加速 I/O、不替代合理索引设计。如果你发现加了直方图后执行计划仍不对,优先检查是否有更合适的索引可建,而不是继续堆直方图。


















