直方图仅在无索引或未命中索引前导列、值分布严重倾斜、且用于where/join/group by中等值或简单范围查询时才被优化器读取;建错类型或桶数反而恶化估算,需通过元数据和explain前后rows变化验证是否生效。

直方图不会让查询“自动变快”,它只在优化器对某列的选择率估算严重失准时才起作用——前提是该列没索引、值分布极不均匀、且出现在 WHERE/JON/GROUP BY 中。
直方图什么时候真正被优化器读取?
它不是写完就生效的装饰品,必须同时满足三个条件才会参与基数估算:
- 目标列上没有可用索引,或虽有索引但查询未命中前导列(比如复合索引
(status, created_at),却只查WHERE created_at > '2025-01-01') - 该列值分布严重倾斜(例如
status中'active'占 92%,其余 15 种状态共占 8%) - 查询中该列用于等值判断(
=、IN)或简单范围(BETWEEN),且未被函数包裹(UPPER(status)或YEAR(created_at)会让直方图失效)
建错类型或桶数,反而让优化器更迷糊
MySQL 只支持 SINGLETON 和 EQ_HEIGHT 两种类型,选错会放大估算误差:
-
SINGLETON:适合低基数离散列(如状态、类型字段),每个唯一值单独记录频次;桶数建议设为唯一值数量 ±20% -
EQ_HEIGHT:适合高基数连续列(如时间戳、金额、用户 ID),桶数建议 100–256;超过 1000 会拖慢解析且元数据膨胀 - 不显式指定
TYPE时默认EQ_HEIGHT,对枚举列大概率误判;字符串列平均长度 > 200 字节可能报ER_TOO_LONG_STRING,需先SUBSTRING(col, 1, 100)
怎么验证直方图真被用了?别信命令是否成功
执行 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 SELECT * FROM t WHERE col = 'x';建直方图前后对比"rows"字段,变化明显(如从 12000 → 380)才说明被采纳 - 注意陷阱:如果查询写了
WHERE UPPER(col) = 'X'或用了隐式类型转换(BIGINT关联VARCHAR),直方图直接失效
最常被忽略的点是:直方图只影响优化器“算多少行”的判断,不改变索引是否存在、也不绕过全表扫描的物理事实。哪怕预估再准,若该列根本没索引,它依然得扫全表——只是这次扫得更有依据而已。











