OPTIMIZE 与 ANALYZE 的区别
InnoDB 的数据放在聚簇索引的页里,大量 DELETE、UPDATE 会在页内留下未回收的空洞(SHOW TABLE STATUS 的 Data_free 就是这块估算值),页分裂还会让逻辑相邻的行落到物理上不相邻的位置。OPTIMIZE TABLE 对 InnoDB 的实际动作是 ALTER TABLE ... FORCE:重建表与索引、把空洞还给表空间。ANALYZE TABLE 不动数据,只重新采样索引基数与直方图,供优化器估算行数。一个管物理空间,一个管统计信息,不能互相替代。
基本信息
| 适用引擎 | InnoDB(MyISAM/Aria 的 OPTIMIZE 行为不同) |
|---|---|
| MySQL 版本 | 5.7 与 8.0 语法一致;8.0 支持列直方图 |
| OPTIMIZE 实质 | ALTER TABLE ... FORCE(重建表 + 重建索引) |
| ANALYZE 实质 | 重新采样索引基数,写入 innodb_index_stats |
| 权限要求 | 对目标表需要 SELECT 与 INSERT 权限 |
| 锁与代价 | OPTIMIZE 期间持元数据锁,需要额外临时空间 |
典型使用场景
- 批量 DELETE 或清理分区后,把空洞占用的磁盘还给表空间
- 大量 UPDATE 让主键顺序与物理顺序严重错位、范围扫描与预读变慢时重建表
- 导入或回滚大批数据后优化器行数估算失真,执行计划突然走错索引
- 报表类大表定期刷新统计信息,避免优化器按旧基数选错连接方式
- 重建前评估空间:临时需要与表数据量相当的空闲磁盘
使用与诊断
使用与诊断
ANALYZE TABLE orders; # 只刷统计信息,轻量,可例行在低峰跑
OPTIMIZE TABLE orders; # InnoDB 上等价重建表,务必低峰执行
CHECK TABLE orders; # 在线一致性检查,不修复数据
ALTER TABLE orders FORCE; # 5.6 起的等价写法,语义更直白
# 看各表数据、索引与碎片估算
SELECT table_name, data_length, index_length, data_free
FROM information_schema.tables WHERE table_schema = 'appdb';
SHOW TABLE STATUS LIKE 'orders'\G # Data_free 偏大说明空洞在累积输出逐列读法
| 列 | 含义 | 怎么判断 |
|---|---|---|
| data_length | 聚簇索引占用字节数 | 含空洞,不等于真实数据量 |
| index_length | 二级索引占用字节数 | 与前一项相加才是总占用 |
| data_free | 已分配未使用的空闲字节 | 持续增长说明碎片在累积 |
| Rows(SHOW 输出) | InnoDB 的采样估算值 | 与 COUNT(*) 有偏差属正常 |
| Create_options | 建表附加选项 | 出现 partitioned 表示是分区表 |
| 磁盘占用对照 | 表空间文件可能大于两列之和 | 与 OS 层 df/du 交叉确认 |
统计信息过期往往比碎片更容易让计划突变:把 ANALYZE TABLE 放进例行维护,或在大批量数据变更后补跑,比事后重建表划算得多。8.0 还能对非索引列建直方图:ANALYZE TABLE t UPDATE HISTOGRAM ON col WITH 64 BUCKETS,属可选增强,不是 OPTIMIZE 的替代。
OPTIMIZE TABLE 在 InnoDB 上是重建操作:需要与表等量的临时空间,会产生大量 redo/binlog,期间该表的写入会被阻塞。在线业务优先用 pt-online-schema-change 或 gh-ost 做等价重建,或先在有数据的从库演练估算耗时。