直方图仅提升优化器对单列等值条件的行数预估精度,不改变执行计划结构;需满足无索引、数据倾斜、用于where/join三个条件才生效,否则无效。

直方图本身不改变执行计划的结构,只让优化器对 WHERE、JOIN 或 GROUP BY 中单列等值条件的行数预估更准——预估准了,它才可能在多个可行路径中选对那个实际更快的。
直方图只在“猜不准”时才被读取
优化器有默认统计(如唯一值数量、平均长度),这些在数据倾斜时完全失效。比如 status 列 95% 是 'active',其余十几种状态加起来才 5%,没直方图时,优化器仍按均匀分布估算 WHERE status = 'cancelled' 返回约 1/16 行数,结果放弃索引走全表扫描;建了直方图后,它知道这个值真实占比仅 0.3%,就更可能选索引查找。
但以下情况直方图压根不会被用到:
- 该列上有可用索引且查询条件命中前导列 → 优化器优先用索引统计,直方图闲置
-
WHERE UPPER(col) = 'X'或WHERE col + 1 > 100这类带函数的条件 → 优化器看到的是表达式结果,无法关联原始列直方图 - 查询涉及多列组合条件(如
WHERE a = ? AND b > ?)→ 直方图只提供单列独立分布,不建模列间相关性
SINGLETON 和 EQ_HEIGHT 必须按列特性选,不能默认
类型选错,轻则精度下降,重则元数据膨胀、解析变慢,甚至让优化器更迷糊:
- 低基数离散值(如
status、is_deleted、枚举字段)→ 用SINGLETON,桶数设为唯一值数量 ±20%。例如 18 种状态,建议WITH 22 BUCKETS - 高基数连续值(如
created_at、user_id、金额)→ 用EQ_HEIGHT,桶数控制在 100–256。超过 1000 会显著拖慢查询解析,且information_schema.COLUMN_STATISTICS体积激增 - 不指定
TYPE时默认EQ_HEIGHT,对只有 4 个值的订单状态列大概率误判,频次信息直接丢失
建完不等于生效,验证必须分两步走
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 这种量级差异才算被采纳
注意:直方图不会把 type: ALL 变成 type: ref,它只影响代价权衡——比如让优化器在“全表扫描”和“走某个二级索引再回表”之间,最终选对那个实际更快的。
真正容易被忽略的是:直方图必须手动更新,且只对等值和简单范围(BETWEEN)有效;字符串列平均长度 > 200 字节时,直接建可能报 ER_TOO_LONG_STRING,得先 SUBSTRING(col, 1, 100) 截断——但截断后匹配精度就打了折扣。











