注册
达梦表空间回收
培训园地/ 文章详情 /

达梦表空间回收

DM_336625 2026/08/19 251 1 0

一、问题现象与初步诊断

现象:数据库表空间的使用率看起来并不高,但其对应的数据文件却非常大,导致磁盘空间告急。常规的ALTER TABLESPACE ... RESIZE DATAFILE ... TO ...命令在尝试收缩数据文件时报错,无法完成。

核心原因:表空间的高水位线(High Water Mark, HWM)之上存在大量已释放但未回收的空间。直接收缩文件会触及其下的数据簇(Extent),因此被达梦机制阻止。

二、解决路径:从报错到清理

2.1 排除事务干扰

报错1表空间上有事务未提交

处理方式:查询并终止阻塞会话。通过关联V$SESSIONSV$LOCK,找到持有事务的会话ID,并使用SP_CLOSE_SESSION系统过程强制关闭。

sql

-- 生成关闭会话的语句
SELECT 'SP_CLOSE_SESSION(''' || sess_id || ''');'
FROM V$SESSIONS
WHERE sess_id != SESSID()
  AND trx_id IN (SELECT trx_id FROM V$LOCK WHERE table_id = 0 AND trx_id <> 0);

2.2 定位“无法回收簇”的根源

报错2无法回收簇

这是核心难点,即RESIZE操作无法越过文件尾部的已占用簇。需要通过一系列系统视图找到“占位”对象。

定位步骤

  1. 确定数据文件:从V$DATAFILE中找到目标数据文件的GROUP_ID(即表空间ID)。
  2. 查找尾部簇:查询V$EXTENTS,按EXTENT_ID降序排列,找出文件尾部(例如EXTENT_ID > 300000)且状态不为FREE的簇记录,记录下这些簇的SEG_ID
  3. 关联对象:通过V$SEGMENT_INFOSSEG_ID映射为OBJ_ID,最后在DBA_OBJECTS中确认对象的名称、类型和所属模式。
select *from SYS.V$DATAFILE;--group_id=17 select *from V$EXTENTS where ts_id=17 order by extent_id desc --使用数据文件的ts_id查SEG_ID select *from v$SEGMENT_INFOS where SEG_ID='111706' --查obj_id33591173 select *from dba_objects where object_id='33627934'---批量查找 select * from dba_objects where object_id in ( select distinct obj_id from v$segment_infos where seg_id in( select seg_id from v$extents where ts_id=17 and state<>'FREE' and seg_id>0 and extent_id >300000 order by extent_id desc )); ---处理 --重构聚集索引。 SP_REORGANIZE_INDEX('CCRM','INDEX33573599'); --重构非聚集索引 ALTER INDEX CCRM.ACRM_F_CI_CST_ADDR_INFO_PK REBUILD ONLINE; SP_REBUILD_INDEX(SCHEMA_NAME varchar(256), INDEX_ID int); ---移动表空间 ALTER TABLE 模式名.表名 MOVE TABLESPACE 目标表空间名; --批量 SELECT 'ALTER TABLE ' || OWNER || '.' || TABLE_NAME || ' MOVE TABLESPACE 目标表空间名;' AS MOVE_SQL FROM DBA_TABLES WHERE OWNER = '你的模式名' -- 例如 'SYSDBA' AND TABLESPACE_NAME = '当前表空间名'; -- 可选,指定从哪个表空间迁出 1. 普通索引会失效,需要重建,需要重新收集统计信息 SELECT OWNER, INDEX_NAME FROM ALL_INDEXES WHERE STATUS = 'UNUSABLE';

处理策略:本次案例中发现有31个对象(表、物化视图等)位于尾部区域。

  • 处理方式:将业务表MOVE到其他表空间,将临时性的物化视图删除。
  • 收尾清理:执行系统过程CALL SP_RECLAIM_TS_FREE_EXTENTS('表空间名');重组空闲簇。若仍无法回收,可在业务低峰期尝试重启数据库。

三、计算安全收缩的目标值

清理完尾部对象后,需要计算能将文件收缩到的最小安全值(即高水位线HWM处的大小)

SELECT c.name AS tablespace_name, a.path AS file_name, CEIL( NVL(b.hwm, 1) * (page/1024.0/1024.0) ) AS "smallest(Mb) - HWM", -- 可以resize到的最小值(MB) a.TOTAL_SIZE * (page/1024.0/1024.0) AS "currsize(Mb)", a.TOTAL_SIZE * (page/1024.0/1024.0) - NVL(b.hwm, 1) * (page/1024.0/1024.0) AS "savings(Mb)" FROM V$datafile a LEFT JOIN ( SELECT ts_id, file_id, MAX(1.0 * EXTENT_ID * SF_GET_EXTENT_SIZE() + USED) AS hwm FROM V$EXTENTS WHERE state NOT IN ('FREE') AND seg_id > 0 GROUP BY ts_id, file_id ) b ON (a.id = b.file_id AND a.group_id = b.ts_id) JOIN V$tablespace c ON a.GROUP_ID = c.ID WHERE a.status$ != 0 AND a.path LIKE '%你的数据文件名%' -- 替换为实际文件 ORDER BY "smallest(Mb) - HWM" DESC;

查询结果中的smallest(Mb) - HWM就是理论上可以RESIZE到的目标值。例如,计算得出目标值为279397MB,则可执行:

ALTER TABLESPACE "表空间名" RESIZE DATAFILE '数据文件名' TO 279397;
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服