直方图仅提升优化器对非索引字段的行数预估精度,不减少实际扫描行数;适用于WHERE/JOIN/GROUP BY中无索引、值分布严重倾斜、EXPLAIN预估与实际行数相差超10倍的列。

直方图不能让非索引列“变快”,它只让优化器对 WHERE 条件的行数预估更准——如果预估从 1 行变成 240 行(真实占比 2.4%),优化器就可能放弃错误的嵌套循环连接,改用哈希连接或调整驱动表顺序。
哪些非索引列值得建直方图
别给所有列都加。只盯住这三类:
- 字段在
WHERE、JOIN或GROUP BY中出现,但没建索引(如status、category、priority) - 值分布严重倾斜:比如
status中'active'占 95%,其余 5% 分散在 10+ 种状态里 -
EXPLAIN FORMAT=JSON显示"rows"预估和实际扫描行数相差超 10 倍(如预估 1 行,SELECT COUNT(*)实际返回 8 万行)
ANALYZE TABLE UPDATE HISTOGRAM 的写法与坑点
语法看着简单,但错一个参数就白忙活:
- 必须显式指定桶数:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 25 BUCKETS;—— 省略WITH N BUCKETS会用默认 100,对小表浪费资源,对高基数列(如user_id)又太粗糙 - 多列要重复写:
UPDATE HISTOGRAM ON status WITH 25 BUCKETS, UPDATE HISTOGRAM ON priority WITH 16 BUCKETS;,不能写成ON status, priority - 需要
SELECT和INSERT权限;若启用了innodb_read_only=ON,语句直接报错ERROR 1290 (HY000) - 执行时持表级只读锁,长事务未结束会被阻塞,务必避开业务高峰
直方图建了但查询没变快?检查这三个盲区
直方图只是辅助估算,以下情况它完全不参与:
- 查询中对列用了函数:
WHERE UPPER(status) = 'ACTIVE'—— 直方图基于原始列值构建,无法匹配 - 表是分区表,且查询条件未命中具体分区(MySQL 8.0.19+ 修复部分场景,但仍有边界)
- 直方图建在从库上,但主库未同步
information_schema.COLUMN_STATISTICS(该表不复制),导致从库EXPLAIN和主库行为不一致
怎么确认直方图真的被优化器用了
别信命令是否成功,要看两处:
- 查元数据:
SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME = 'orders' AND COLUMN_NAME = 'status';—— 返回非空 JSON 才算写入成功 - 比对
EXPLAIN FORMAT=JSON:SELECT * FROM orders WHERE status = 'done';建直方图前后分别执行,观察"rows"字段是否明显趋近真实值(比如从 10000 变成 240)
真正容易被忽略的是:直方图不会改变执行计划类型(比如不会把 type: ALL 变成 type: ref),它只影响优化器内部的基数估算逻辑——这意味着你得盯着 "rows" 和连接顺序变化,而不是看有没有“走索引”。


















