直方图本身不加速查询,只提升优化器对非索引列选择率的估算精度;它通过分桶记录值频次,解决数据倾斜导致的预估偏差(如预估1行、实际扫30万行),但仅在无索引、无函数包裹、预估误差超10倍且非分区表等条件下生效。

直方图本身不加速查询,它只让优化器对 WHERE 条件中非索引列的选择率估算更准——这直接影响执行计划是否合理。如果预估严重偏差(比如预估 1 行、实际扫 30 万行),优化器可能错选全表扫描,而直方图能帮它“看出”低频值的存在。
直方图解决的是优化器的“瞎猜”问题
MySQL 默认统计信息只记录 min/max、唯一值数量、平均长度等粗粒度指标。当字段严重倾斜(如 status 列中 'active' 占 95%,'cancelled' 仅占 0.2%),优化器会按“均匀分布”假设估算:查 'cancelled' 也大概率预估为总行数 × 1/N,结果远高于真实值。直方图把值域切分成桶(SINGLE_VALUE 或 TARGET 类型),显式记录每个高频值或值区间的出现频率,让优化器知道“这个值真稀少”。
必须满足这四个条件才可能生效
直方图不是开关一开就提速,它只在特定组合下参与决策:
- 字段未建索引(否则优化器优先走索引,直方图被忽略)
- 查询条件直接使用列名,不能包裹函数(如
WHERE UPPER(status) = 'CANCELLED'→ 直方图失效) -
EXPLAIN中rows预估值与实际扫描行数相差超 10 倍(否则说明当前统计已够用) - 表不是分区表,或查询条件已精准命中分区(分区表 + 直方图在 MySQL 8.0.19+ 才部分支持)
ANALYZE TABLE ... UPDATE HISTOGRAM 的关键参数怎么选
桶数(BUCKETS)不是越多越好,要匹配数据特征:
- 枚举类/低基数列(如
status、gender):25–100 桶足够;SINGLE_VALUE类型自动启用,能精确记录每个值频次 - 高基数列(如
user_id、created_at):100–256 桶较稳妥;超过 1000 桶会显著增大information_schema.COLUMN_STATISTICS体积,且解析开销上升 - 字符串列若平均长度 > 200 字节,建直方图可能报
ER_TOO_LONG_STRING;可临时用SUBSTRING(col, 1, 100)截断,但精度下降 - 大表建直方图可能吃内存,可通过
histogram_generation_max_mem_size限制采样内存上限,触发后自动降级为采样分析
验证直方图是否真正起作用
别只信命令返回 Query OK,得看两处:
- 查元数据:
SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME = 'orders' AND COLUMN_NAME = 'status';返回非空 JSON 才算写入成功 - 对比执行计划变化:对低频值执行
EXPLAIN FORMAT=JSON,观察query_block->condition_filtering_probability是否明显提升(如从 0.001 → 0.0002) - 注意:直方图不会让
type: ALL变成type: ref,它只影响rows预估和后续连接顺序、物化策略等二级决策
最容易被忽略的一点:直方图是手动更新的,ANALYZE TABLE 不会自动触发它,数据批量变更后必须显式运行 UPDATE HISTOGRAM,否则优化器仍在用过期分布做判断。


















