OPTIMIZE TABLE 和 ANALYZE TABLE 的区别:用实测数据说话原创
版本说明
本文基于 MySQL 8.0 InnoDB 引擎验证,OPTIMIZE TABLE 在 InnoDB 上的实现机制自 5.6 起沿用至今。
OPTIMIZE TABLE 和 ANALYZE TABLE 都归在 MySQL"表维护"命令下,容易被当成同一类操作混用,但它们解决的是完全不同的问题——一个动数据物理布局,一个只更新统计信息,代价和适用场景天差地别。
# 1. OPTIMIZE TABLE:重建表,清理碎片
对 InnoDB 表,OPTIMIZE TABLE 实际上等价于:
ALTER TABLE table_name ENGINE=InnoDB;
也就是整表重建——把表的所有数据按主键顺序重新写入一份新的物理文件,旧文件里因为频繁 DELETE/UPDATE 产生的空洞(碎片)在重建过程中被清理掉,索引也一并重建。
怎么量化碎片程度,先看这张表:
SELECT
table_name,
data_length,
data_free,
ROUND(data_free / (data_length + data_free) * 100, 2) AS frag_pct
FROM information_schema.tables
WHERE table_schema = 'your_db' AND table_name = 'your_table';
2
3
4
5
6
7
data_free 是表文件中"已分配但未使用"的空间(碎片),frag_pct 是碎片占比的粗略估算。经验上 frag_pct 超过 20%~30% 才值得考虑做一次 OPTIMIZE TABLE,碎片率低的时候没有必要。
实测参考(某张频繁增删的日志表,200 万行,执行前后对比):
| 指标 | 执行前 | 执行后 |
|---|---|---|
表文件大小(data_length + data_free) | 4.2 GB | 2.6 GB |
data_free(碎片) | 1.7 GB | ~0 |
全表扫描耗时(SELECT COUNT(*)) | 3.8s | 2.1s |
数据仅供量级参考,具体收益取决于碎片率高低、行大小、硬件 I/O 能力,不能直接套用到别的表。碎片率低(比如 5% 以下)的表上跑 OPTIMIZE TABLE,物理文件几乎不会缩小,但依然要付出整表重建的代价——这是很多人误用它的地方:"定期无脑跑一遍 OPTIMIZE" 不是好习惯,应该先测碎片率,超过阈值再动手。
坑(重要):InnoDB 上 OPTIMIZE TABLE 本质是 ALTER TABLE,会对表加锁并触发数据重建,大表执行期间会显著占用 I/O 且可能长时间锁表(虽然 InnoDB 支持 Online DDL,多数场景下允许并发 DML,但重建过程本身的资源开销依然很高)。生产环境务必安排在业务低峰期,且对大表(几十 GB 以上)先在测试环境估算耗时。
# 2. ANALYZE TABLE:只更新统计信息,不动数据
ANALYZE TABLE table_name;
ANALYZE TABLE 不重建任何数据,只是重新采样、计算索引列的基数(cardinality,即不同值的数量)等统计信息,写回 information_schema 供优化器在生成执行计划时参考——这正是本系列 17.MySQL为什么有时候会选错索引 里提到的"统计信息不准确"问题的直接解药。
因为不涉及数据重写,ANALYZE TABLE 的执行速度和资源消耗远小于 OPTIMIZE TABLE——即使是几千万行的大表,通常也是秒级到几十秒级完成(采样统计,不是全表扫描)。
什么时候该跑:表的数据分布发生较大变化后(大批量导入/删除、字段值分布明显改变),或者发现执行计划开始选错索引、possible_keys 里有更优索引但没被选中时。
# 3. 两者的核心区别
OPTIMIZE TABLE | ANALYZE TABLE | |
|---|---|---|
| 做什么 | 重建表物理文件,清理碎片 | 重新采样统计信息(如索引列基数) |
| 代价 | 高(整表重建,锁表/I/O开销大) | 低(采样统计,秒级完成) |
| 解决的问题 | 表文件臃肿、碎片率高 | 优化器选错执行计划 |
| 触发场景 | 碎片率超过阈值(如 20%+) | 数据分布变化大,或发现执行计划异常 |
| 频率建议 | 按需,不建议定期无脑跑 | 可以相对更频繁(代价低) |
# 4. 可复用要点
- 判断要不要跑
OPTIMIZE TABLE,先用information_schema.tables的data_free算碎片率,别凭感觉定期跑。 OPTIMIZE TABLE在 InnoDB 上等价于整表重建,代价远高于ANALYZE TABLE,大表操作务必选低峰期。- 遇到"执行计划选错索引"先怀疑统计信息过期,跑
ANALYZE TABLE(代价低);遇到"表文件占用异常大"再考虑OPTIMIZE TABLE。
- 01
- ORDER BY 配合 LIMIT 触发的索引选择陷阱 原创08-07
- 02
- Nginx 运维知识地图:从配置基础到反向代理实战 原创07-29
- 03
- MySQL 运维知识地图:从入门配置到高可用排障 原创07-29