表空间“满”需先区分碎片、AWR快照堆积或大表持续写入等真因,再针对性处理;盲目删数据易致锁表、AWR失效或元数据损坏。
表空间满了不能直接删数据就完事,得先搞清“满”是假象还是真危机——比如碎片太多导致无法分配新区段,或者 sysaux 里 awr 快照堆到爆,又或是某个大表没归档还在狂写。盲目 drop 或 truncate 可能引发锁表、awr 报告失效、甚至元数据损坏。
查清楚到底是谁占了空间
别一上来就删。先跑这条 SQL 定位“重灾区”:
SELECT owner, segment_name, segment_type,
ROUND(bytes/1024/1024/1024, 2) AS gb
FROM dba_segments
WHERE tablespace_name = 'YOUR_TABLESPACE_NAME'
ORDER BY bytes DESC
FETCH FIRST 10 ROWS ONLY;
重点关注 segment_type 是 TABLE、INDEX 还是 LOBSEGMENT,尤其是 WRH$_ 开头的(说明是 AWR 堆表),这类不能手删。如果发现某张业务表占了几十 GB,再查它有没有历史分区或未清理的归档字段。
- SYSAUX 表空间爆满?优先查
dba_hist_snapshot和dba_hist_database_instance,确认快照是否堆积 - USERS 或业务表空间里大表多?用
dba_tab_partitions看是否该上分区策略 - 最大连续空闲块(
MAX(fs.bytes))远小于你要分配的区段大小?说明是碎片问题,不是真没空间
删旧数据前必须确认三件事
DELETE 或 TRUNCATE 不是按钮,是手术。执行前务必核对:
- 目标表是否有外键被其他模块引用?
TRUNCATE会失败,得先DISABLE CONSTRAINT - 是否启用了 Flashback Data Archive?删了也恢复不了,但误删可能触发归档异常
- 表是否在复制或 GoldenGate 同步链路中?
TRUNCATE默认不记入 redo,下游可能丢数据 - 用
DELETE清理时,记得加COMMIT,否则事务撑爆回滚段;大表建议分批,比如WHERE create_time 加 <code>ROWNUM
真要清空整表且结构保留,TRUNCATE TABLE t REUSE STORAGE 比 DELETE 快,但不会降低 HWM(高水位线),后续 INSERT 仍从高位开始写。
删完不等于空间就回来了
Oracle 不会自动把空间还给操作系统,尤其数据文件本身不会缩小。常见误区:
-
DROP TABLE ... PURGE只删段,不缩数据文件;ALTER TABLESPACE ... SHRINK仅适用于本地管理 + ASSM 表空间,且要求段支持 shrink(比如非LOB或INDEX ORGANIZED) - AWR 快照删完,
SYSAUX表空间的物理文件大小不变,必须手动ALTER DATABASE DATAFILE ... RESIZE,但得先确保dba_free_space显示顶部有足够连续空闲 - 重建索引(
ALTER INDEX i REBUILD)能释放索引段碎片,但对基表空间无影响;若表本身有大量删除,得配合SHRINK SPACE CASCADE或MOVE
例如收缩一张大表:ALTER TABLE t ENABLE ROW MOVEMENT; ALTER TABLE t SHRINK SPACE CASCADE; —— 这步会移动行、重排块、更新索引,但要求表空间是 ASSM,且不能有 NOLOGGING 操作正在跑。
SYSAUX 专用:AWR 快照不能手删表
看到 WRH$_SQLSTAT 占满 SYSAUX?千万别 DROP TABLE WRH$_SQLSTAT 或 DELETE FROM dba_hist_sqlstat。后果是 AWR 报告报 ORA-13516,甚至整个 awrrpti.sql 脚本失效。
- 先调低保留时间:
EXEC DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(retention => 25920);(7天) - 等自动清理窗口(默认凌晨2点)或手动删范围:
EXEC DBMS_WORKLOAD_REPOSITORY.DROP_SNAPSHOT_RANGE(1000, 2000); - 删完立刻查
dba_free_space,如果最大连续块没变大,说明 HWM 没动,得对底层WRH$_表所在段执行SHRINK(需 Oracle Support 确认是否安全)
最麻烦的是 dba_hist_database_instance 里出现重复 DBID + 错乱 STARTUP_TIME,这会导致跨实例 AWR_DIFF_REPORT 失效,只能靠 DBMS_SWRF_INTERNAL 修复——但那是 Oracle 内部包,生产环境严禁自行调用。


















