加including contents and datafiles是必要条件但非充分条件;因oracle 19c在linux/unix下调用unlink()删除文件,若dbwn、ckpt等进程仍持有文件句柄,内核不释放磁盘块,故df -h无变化,需检查lsof确认deleted状态并杀进程或重启实例。

加 INCLUDING CONTENTS AND DATAFILES 是必要条件,但不是充分条件——不检查依赖和会话,语句可能成功返回,磁盘空间却一动不动。
为什么 DROP TABLESPACE 后 df -h 看不到空间释放?
Oracle 19c 在 Linux/Unix 上执行 DROP TABLESPACE ... INCLUDING CONTENTS AND DATAFILES 时,实际调用的是 unlink() 系统调用。只要还有 Oracle 进程(比如 DBW0、CKPT)持有该数据文件的 file descriptor,内核就不会真正回收磁盘块。
典型现象:
-
lsof | grep 'deleted'能看到类似/u01/oradata/ORCL/ts_old01.dbf (deleted)的输出 -
df -h显示空间未变化,但SELECT file_name FROM dba_data_files WHERE tablespace_name = 'TS_OLD'已查不到记录
这不是 bug,是 Unix 文件系统语义决定的:只要 inode 被引用,空间就不可重用。
删之前必须确认的四件事
跳过任意一项,轻则报错中断,重则删错系统表空间或留下残留对象。
- 确认不是系统表空间:
SELECT * FROM dba_tablespaces WHERE tablespace_name IN ('SYSTEM', 'SYSAUX', 'UNDOTBS1', 'TEMP') - 确认没被设为用户默认表空间:
SELECT username, default_tablespace FROM dba_users WHERE default_tablespace = 'TS_OLD',若有需先执行ALTER USER xxx DEFAULT TABLESPACE users - 确认无活跃会话正在使用该表空间:
SELECT sid, serial#, username FROM v$session WHERE username IN (SELECT username FROM dba_users WHERE default_tablespace = 'TS_OLD');有则用ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE - 确认无 Flashback Data Archive 或 GoldenGate 依赖:
SELECT * FROM dba_flashback_archive_tables WHERE tablespace_name = 'TS_OLD';如有,得先迁移或禁用
删完空间没回收?两种可靠处理方式
优先选方式一(轻量),方式二仅在方式一无效或环境受限时启用。
-
方式一:kill 持有句柄的后台进程
执行lsof | grep 'ts_old.*deleted'找出 PID(通常是DBW0、DBW1);
用kill -9 <pid></pid>干掉对应进程;
等待 10–30 秒,df -h通常立即更新 -
方式二:重启数据库实例
SHUTDOWN IMMEDIATE强制关闭所有文件句柄;STARTUP启动后,内核真正回收空间;
注意:控制文件、联机日志路径必须有效,否则启动失败
容易被忽略的细节
很多人以为加了 AND DATAFILES 就万事大吉,其实还有几个硬坑:
-
INCLUDING CONTENTS必须写在AND DATAFILES前面,否则报ORA-01911 - ASM 环境下
AND DATAFILES不起作用,得走ALTER DISKGROUP ... DROP FILE流程 - Windows 下若 Oracle 服务账户无 NTFS 删除权限,.dbf 文件可能残留,需手动进目录删(先停库)
- 外键跨表空间引用时,不加
CASCADE CONSTRAINTS会直接报ORA-02449,但该子句只删约束定义,不影响其他表空间的数据
真正麻烦的从来不是命令敲错,而是没盯住 v$session 和 v$sort_usage 的实时状态——尤其在高负载时段删临时表空间时,一个未结束的排序操作就能卡住整个流程。











