bigywater.tech
MySQL / InnoDB · 33

Histogram 直方图

用ANALYZE TABLE UPDATE HISTOGRAM给一个无索引的倾斜分布列建直方图,验证它是怎么修正行数估算的,以及一个的操作顺序陷阱。

20000→188774
先ANALYZE再建直方图,修正到接近准确
27.5
顺序反了时更离谱的估算
0.9499951
直方图精确记录的累积频率

做的事:给一个没有索引的列建直方图

直方图是为"没有索引可用"的列设计的选择性估算工具。

建表插入CREATE TABLE t15 (id INT PRIMARY KEY AUTO_INCREMENT, status VARCHAR(20), payload VARCHAR(100)); 插入20万行,95%概率status='active',status上没有任何索引

验证:没有索引也没有直方图时,估算是个固定的"拍脑袋"数字

对比建直方图前后的行数估算。

结果建直方图之前: EXPLAIN SELECT * FROM t15 WHERE status='active' → rows=20000 (固定的10%估算,的active占比是95%,完全不沾边) 执行 ANALYZE TABLE t15 UPDATE HISTOGRAM ON status WITH 10 BUCKETS 之后再EXPLAIN: → rows=27.5 (更离谱了!)

第一次尝试的结果很意外:单独执行 UPDATE HISTOGRAM(不先做普通的 ANALYZE TABLE)之后,估算从"错得离谱的20000"变成了"错得更离谱的27.5"。

验证:先跑普通ANALYZE TABLE,直方图才起作用

这是一个容易被忽视的操作顺序问题。

结果执行普通 ANALYZE TABLE t15(不带HISTOGRAM) EXPLAIN SELECT * FROM t15 WHERE status='active' → rows=188774 (的active数量是189960,误差已经缩小到约0.6%!) 这之后再补跑一次 UPDATE HISTOGRAM → rows=188639 (依然准确,没有变差)
发现的操作顺序陷阱是:ANALYZE TABLE ... UPDATE HISTOGRAM 只更新直方图这一份统计信息,不会顺带刷新这张表的基础表级统计信息(比如总行数)——如果这张表本来就从没跑过普通的 ANALYZE TABLE,表级统计信息可能还停留在很不准的默认状态,直方图的选择性比例信息叠加在一个错误的基数上,反而会算出比"完全没有统计信息"更离谱的结果。正确的顺序应该是:先跑一次普通 ANALYZE TABLE 把基础统计打好底,再叠加 UPDATE HISTOGRAM 补充分布形状信息——顺序反了,会踩到这个坑。

验证:直方图本身的内容,是什么样

用information_schema能看到直方图存的原始数据。

结果(查复用的t3b表,同样95%/5%分布)SELECT HISTOGRAM FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME='t3b' AND COLUMN_NAME='status' 直方图类型: singleton(离散值直方图,适合status这种低基数列) 采样率: 0.372 bucket数: 2 ['base64:...YWN0aXZl'(active), 0.9499951370652884] ← 累积频率精确对应95% ['base64:...YmFubmVk'(banned), 1.0]

的直方图内容比想象中直白:每个bucket记录一个具体的值(base64编码),加上"截止到这个值,累积占了整体的百分之多少"——active的累积频率是0.9499951,跟本系列前面测出的95%占比几乎完全吻合,这就是直方图为什么能准确捕捉到这种极端倾斜分布的原因:它记录的是的值分布形状,不是像普通索引统计那样只给一个笼统的"不同值数量"估算。

分步演示:直方图是怎么修正(以及意外恶化)估算的

每一步都是本文上面用EXPLAIN和information_schema跑出来的原始结果。

直方图能修正估算,但顺序不对反而更糟
这一步新验证的场景

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),无索引倾斜分布表
    • ANALYZE TABLE ... UPDATE HISTOGRAM / information_schema.COLUMN_STATISTICS:验证直方图效果与顺序陷阱
    京ICP备2026067502号-1京公网安备11010502063487号