直方图仅提升优化器对where条件选择率的估算精度,不强制改变索引使用;type: all与直方图无关,其生效需满足列用于关键过滤、无可用索引或值分布不均等前提。

直方图本身不会“避免”索引走法,它只让优化器对 WHERE 条件的选择率(filtered)估算更准——当这个估算变准了,原本因误判而放弃的索引,才可能被重新选中;反之,原本因高估而错误选择的索引,也可能被放弃。它不强制走或不走索引,只修正“算错”的那部分代价判断。
为什么加了直方图,EXPLAIN 还是 type: ALL?
这是最常被误解的点。type: ALL 表示访问方式没变,和直方图无关;直方图只影响优化器内部的行数预估(rows)和过滤比例(filtered),不改变物理扫描逻辑。常见绕过场景包括:
-
WHERE UPPER(status) = 'ACTIVE':函数包裹后,优化器看到的是表达式结果,不是原始列,直方图失效 - 字段类型为
JSON、GEOMETRY或压缩的TEXT:MySQL 当前版本不支持为其建直方图,语句静默跳过 - 查询涉及分区表,但条件未精确匹配分区键(如按
region分区,却查WHERE created_at > '2025-01-01'):直方图元数据不会加载 - 建完直方图没执行
ANALYZE TABLE t;:优化器默认不自动重载,必须显式触发统计刷新
如何验证直方图是否真正影响索引选择?
不能只看 Query OK,得查两处真实证据:
- 查元数据是否存在:
SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 'orders' AND COLUMN_NAME = 'status';——返回非空 JSON 才算落地成功 - 对比
EXPLAIN FORMAT=JSON输出中的"filtered"字段:对低频值(如WHERE status = 'failed')执行前后对比,若从10.00→0.37,说明优化器已采纳 - 注意观察
"rows"是否同步变化:如果filtered变了但rows没变,大概率是没触发统计重载,需补一次ANALYZE TABLE orders;
选错直方图类型或桶数,反而让优化器更迷糊
关键看列值分布特征,不是凭感觉:
- 低基数离散值(如
status、order_type、布尔字段)→ 必须用SINGLETON类型,桶数设为唯一值数量 ±20%。例如 12 种状态,写WITH 14 BUCKETS TYPE SINGLETON - 高基数连续值(如
created_at、user_id、金额)→ 用EQ_HEIGHT(MySQL 默认),桶数控制在 100–256。超过 1000 会拖慢查询解析,且information_schema.COLUMN_STATISTICS表体积激增 - 字符串列平均长度 > 200 字节时,直接建直方图可能报
ER_TOO_LONG_STRING;可临时截断:ANALYZE TABLE orders UPDATE HISTOGRAM ON SUBSTRING(status, 1, 100) WITH 20 BUCKETS;,但要注意精度损失
直方图生效的前提是:列用于关键过滤条件、无可用索引(或条件未命中索引前导列)、值分布严重不均。三者缺一不可。它不替代索引设计,也不修复 SQL 写法问题,比如 LIKE '%abc' 或多列组合条件,直方图基本无效。











