truncate立即释放表空间,delete不释放(innodb默认行为):truncate直接丢弃数据段并重建空表,配合innodb_file_per_table=on可显著缩小.ibd文件;delete仅标记删除、不缩表,须执行optimize table才能真正释放磁盘空间。

TRUNCATE 立即释放表空间,DELETE 不释放(InnoDB 默认行为)
在 MySQL 的 InnoDB 引擎下,DELETE FROM table_name 即使删光所有行,也不会缩小 .ibd 文件大小,表所占磁盘空间基本不变。这是因为 DELETE 只是把行标记为“已删除”,物理块仍被该表逻辑占用,后续插入可复用这些空间,但不会返还给操作系统。
TRUNCATE TABLE table_name 则不同:它直接丢弃原数据段,重建空段,系统会把对应的数据页全部归还给表空间,.ibd 文件实际尺寸显著减小(需配合 innodb_file_per_table=ON 才可见文件收缩)。
-
DELETE后查information_schema.tables的DATA_LENGTH基本不变 -
TRUNCATE后同字段值会骤降至接近表结构本身大小(如几 KB) - MyISAM 表例外:
DELETE会立即释放磁盘空间,但该引擎已基本淘汰
想让 DELETE 释放空间?必须手动执行 OPTIMIZE TABLE
DELETE 删除后若要真正腾出磁盘空间,不能只靠 COMMIT,必须额外运行 OPTIMIZE TABLE table_name。这个命令会重建表、整理碎片、重写 .ibd 文件,并将未使用的空间交还给文件系统。
-
OPTIMIZE TABLE是 DDL 操作,会锁表(尤其大表耗时久) - 执行后,
DATA_LENGTH和磁盘上.ibd文件大小同步下降 - 在高可用或读写密集场景中,应避开业务高峰执行
- 注意:MySQL 8.0+ 对某些 Online DDL 支持更好,但
OPTIMIZE仍非完全无锁
TRUNCATE 的空间释放依赖存储引擎和配置
TRUNCATE 是否真能缩小物理文件,取决于底层引擎和配置项。最关键是:innodb_file_per_table 必须为 ON(MySQL 5.6.6+ 默认开启)。如果关闭,所有表共享 ibdata1,TRUNCATE 仅释放内部页,不减少 ibdata1 大小。
- 确认方式:
SELECT @@innodb_file_per_table;返回1才有效 - 即使
TRUNCATE成功,若表有大量二级索引,重建过程仍可能短暂占用额外空间 - 部分云数据库(如阿里云 RDS)默认开启独立表空间,但需检查实例参数
误判空间是否释放?别只看 rows 或 show table status
很多人用 SHOW TABLE STATUS LIKE 'table_name' 或 SELECT COUNT(*) 判断空间是否释放,这是错的。Rows 字段是估算值,Data_length 字段才反映实际数据页占用——但要注意它不含索引空间。
- 准确查磁盘占用应组合使用:
SELECT CONCAT(ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2), ' MB') AS size FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'db_name' AND TABLE_NAME = 'table_name'; - Linux 下还可直接
ls -lh /var/lib/mysql/db_name/table_name.ibd查物理文件大小 - 监控时发现
DELETE后空间没变,别急着怀疑 SQL 写错,先确认是否漏了OPTIMIZE或引擎限制
TRUNCATE 的空间释放效果立竿见影,但代价是不可回滚、不触发约束与触发器;DELETE 看似“温柔”,却常因忽略 OPTIMIZE 导致磁盘悄悄吃紧——这点在长期运行的归档表或日志表上特别容易被忽视。











