delete后磁盘空间不释放是innodb正常行为,因其仅逻辑标记删除行、不物理回收页空间;必须通过optimize table或alter table engine=innodb重建表才能真正释放.ibd文件空间。

DELETE后磁盘没变小,不是SQL写错了
执行DELETE后du -h table.ibd或sp_spaceused显示空间纹丝不动,这是正常行为,不是你漏写了WHERE、没提交事务,也不是数据库配置错。InnoDB 和 SQL Server 都只做逻辑标记:InnoDB 翻转行头的delete_mask位,SQL Server 在数据页打“已删除”标记——物理页不挪、文件不缩、操作系统完全看不到“空”。被删的页仍属于.ibd或.mdf文件,后续INSERT会优先复用它们。
MySQL怎么真正缩表:OPTIMIZE TABLE 的硬条件
OPTIMIZE TABLE t本质是重建:新建空表 → 拷贝有效行 → 原子替换。但它不是万能开关,必须同时满足:
-
innodb_file_per_table = ON(5.6+默认开启,但老实例常被手动关掉;若为OFF,所有表空间都在ibdata1里,OPTIMIZE完全无效) - 无长事务阻塞:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 600结果为空,否则卡在Waiting for table flush - 磁盘剩余空间 ≥ 当前
Data_length的1.5倍(重建过程要落临时表+redo log) - RDS/PolarDB等托管服务可能禁用该命令,或自动路由到只读副本执行——得先查控制台文档
示例:OPTIMIZE TABLE api_logs;执行后对比ls -lh api_logs.ibd前后大小,可验证是否生效。
SQL Server别乱用DBCC SHRINKDATABASE
DBCC SHRINKDATABASE确实能截断文件尾部,但代价极高:
- 触发全库级页移动,聚集索引
avg_fragmentation_in_percent大概率飙到60%以上 - 若启用了
READ_COMMITTED_SNAPSHOT,收缩过程可能被快照版本链阻塞 - 它不跨文件组生效——大表若在
SECONDARY文件组,只对PRIMARY收缩毫无意义
更稳妥路径是:
堆表全删后:ALTER TABLE dbo.LogTable REBUILD WITH (DATA_COMPRESSION = PAGE);
聚集表优先:ALTER INDEX ALL ON dbo.Orders REBUILD;
仅磁盘告警时才单文件收缩:DBCC SHRINKFILE('MyDB_Data', 10240)(目标10GB),且收缩后必须立刻REBUILD索引。
SQLite和Oracle的处理逻辑完全不同
SQLite用VACUUM——它重建整个数据库文件,释放空闲页并缩小.db文件,但会阻塞写入;Oracle则靠ALTER DATABASE DATAFILE ... RESIZE手动缩数据文件,前提是先确认dba_free_space里有连续空块,且文件末尾无活动段。误删文件后df -h不释放,是因为OS句柄仍被进程持有,需lsof | grep deleted找PID杀掉,或重启实例。











