MySQL 直方图统计信息怎样帮助优化器选择计划
来源:17golang原创
时间:2026-10-28 23:15:37 400浏览 收藏
MySQL 直方图不是索引,也不会强制优化器选择某个索引;它补充的是列值分布信息。对于值分布倾斜、但仅靠普通统计信息难以估准选择率的列,优化器可以利用直方图更接近地估算过滤后会剩下多少行,从而比较不同执行计划。
官方资料:https://dev.mysql.com/doc/refman/8.4/en/optimizer-statistics.html
- 用
ANALYZE TABLE ... UPDATE HISTOGRAM为具体列生成统计信息,默认 100 个桶,也可以显式指定 1 到 1024 个桶。 - 用
INFORMATION_SCHEMA.COLUMN_STATISTICS查看直方图 JSON、类型、桶数和sampling-rate,再用EXPLAIN对照优化器估算。 - 直方图依赖数据分布的新鲜度;效果不合适时先重新生成,仍不需要时用
DROP HISTOGRAM清除。
直方图到底补充了哪类统计信息
优化器需要估算条件会命中多少行,才能在索引、扫描、连接顺序等候选计划之间做比较。单一的基数或平均分布假设,在列值高度倾斜时可能不够:例如某个状态值占了绝大多数行,另一些状态几乎没有数据,同样的列却对应完全不同的过滤选择率。
直方图把列值范围或离散值整理成多个桶,并把这些分布摘要保存在数据字典中。用户通过 INFORMATION_SCHEMA.COLUMN_STATISTICS 读取视图,不直接操作底层数据字典表。它提供的是优化器参考信息,不是查询结果缓存,也不会替代合适的索引。

用 ANALYZE TABLE 为目标列生成直方图
先挑选真正参与过滤、分布明显不均匀或估算经常偏差的列,而不是给整张表的所有列都建立直方图。最小语句如下:
-- 为 orders.status 生成直方图,帮助优化器了解状态值分布。 ANALYZE TABLE orders UPDATE HISTOGRAM ON status; -- 需要更细的分布摘要时显式指定桶数量。 ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 64 BUCKETS;
UPDATE HISTOGRAM 语法一次只针对一张表;同一语句可以列出多个目标列。WITH N BUCKETS 的 N 范围是 1 到 1024,省略时默认 100。桶越多不等于计划一定越好,还要考虑生成成本、数据规模和分布复杂度。
该操作需要目标表的 SELECT 和 INSERT 权限。MySQL 8.4 文档还说明,几何类型和 JSON 列不支持直方图,单列唯一索引覆盖的列也不能生成直方图;临时表和加密表同样不在可用范围内。
先查看 COLUMN_STATISTICS,再判断估算是否有依据
生成后不要只看语句返回成功,还要知道统计信息是否确实存在、采样比例是多少:
-- 读取指定表和列的直方图摘要,避免把别的表混在一起看。
SELECT SCHEMA_NAME,
TABLE_NAME,
COLUMN_NAME,
HISTOGRAM
FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
WHERE SCHEMA_NAME = DATABASE()
AND TABLE_NAME = 'orders'
AND COLUMN_NAME = 'status';
-- 只取采样比例,1.0 表示生成时读取了全部数据。
SELECT HISTOGRAM->>'$."sampling-rate"' AS sampling_rate
FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
WHERE SCHEMA_NAME = DATABASE()
AND TABLE_NAME = 'orders'
AND COLUMN_NAME = 'status';
返回的 HISTOGRAM 是 JSON 对象,常见信息包括 histogram-type、number-of-buckets-specified、last-updated、null-values 和 sampling-rate。sampling-rate 小于 1 说明生成过程采用了采样,不能把桶看成完整数据的逐行复刻。
如果生成期间需要读取的数据超过 histogram_generation_max_mem_size,MySQL 会改为采样;可以通过这个字段判断当前直方图的依据是否足够覆盖业务数据。这里的判断重点是“统计信息是否新鲜、是否有采样、是否与当前过滤场景相符”,而不是单独追求一个更大的桶数。

用 EXPLAIN 对照计划,别把直方图当成强制提示
直方图是否真正改变了优化器选择,要回到具体查询观察估算行数、访问方式和过滤条件。可以在生成前后分别保存同一条查询的计划:
-- 用同一条查询对照估算行数和访问方式,避免把查询文本也一起改掉。 EXPLAIN FORMAT=JSON SELECT order_id, created_at FROM orders WHERE status = 'pending';
重点对照的是估算行数、过滤条件对应的选择率以及访问路径是否更符合数据分布。计划变化本身不是成功标准:如果直方图过期、采样不足,或者优化器基于新估算选择了更差的路径,查询仍可能变慢。应在接近真实数据量和真实条件的环境中,用同一条 SQL、同一组参数做前后对照。
直方图也不能表达任意列之间的相关性。两个条件分别看似稀疏,组合起来可能高度相关;单列直方图并不会自动得到完整的多列联合分布。因此它适合补充某个列的分布估计,不应被当成“有了统计信息就能解决所有计划问题”。
桶数量、采样与自动更新怎么取舍
小桶数适合分布简单、维护成本敏感的列;分布有多个明显密集区时,可以增加桶数,但要用 HISTOGRAM 的桶数和 sampling-rate 一起判断。只调大桶数而不关注数据是否采样,可能只是让摘要更复杂,并没有带来等比例的估算收益。
-- 让后续持久化统计更新时按同样桶数自动更新该列直方图。 ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 64 BUCKETS AUTO UPDATE; -- 如果自动更新带来的计划变化不符合预期,删除这一列的直方图。 ANALYZE TABLE orders DROP HISTOGRAM ON status;
AUTO UPDATE 会启用自动更新;不写时默认是 MANUAL UPDATE。自动更新依赖持久化统计信息的更新机制,并不意味着每次 DML 完成后直方图都会立刻同步。若数据刚完成大批量导入、分布发生明显变化且需要立即刷新,显式执行 ANALYZE TABLE 更直接。
常见问题
直方图会不会强制 MySQL 使用某个索引?
不会。它提供列值分布摘要,影响的是优化器的估算依据;最终计划仍由优化器结合成本、索引和其他条件决定。
桶数是不是越大越好?
不是。桶数要与分布复杂度、表规模、生成成本和采样情况一起看。先用默认值观察估算,再针对确有偏差的列调整。
什么时候应该删除直方图?
当数据分布已变化、统计信息长期过期,或对照同一查询发现新计划持续变差时,可以先重新生成;如果该列不再需要分布摘要,再执行 DROP HISTOGRAM 清除。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
257 收藏
-
369 收藏
-
191 收藏
-
499 收藏
-
209 收藏
-
308 收藏
-
423 收藏
-
389 收藏
-
161 收藏
-
500 收藏
-
121 收藏
-
188 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习