查DBA_SEGMENTS定位最大空间占用对象:执行SELECT语句列出目标表空间前10大段,关注segment_type(TABLE/INDEX/LOB)和owner(SYSTEM/SYSAUX需谨慎),结合v$session与dba_extents追踪活跃写入会话,并同步检查UNDO、TEMP使用率及自动扩展与碎片化问题。
查 DBA_SEGMENTS 定位最大空间占用对象
表空间爆满时,真正“吃掉”空间的不是sql语句本身,而是它生成或修改的段(segment)——比如表、索引、lob、分区等。所以第一步必须绕过“谁在跑sql”的表象,直接查物理存储分配情况。
执行以下查询可快速列出目标表空间中前10个最大段:
SELECT owner, segment_name, segment_type, partition_name,
ROUND(bytes/1024/1024/1024, 2) size_gb
FROM dba_segments
WHERE tablespace_name = 'USERS' -- 替换为你的表空间名,注意大小写
ORDER BY bytes DESC
FETCH FIRST 10 ROWS ONLY;
-
segment_type是关键线索:若大量是TABLE或INDEX,说明业务数据/索引膨胀;若是LOBSEGMENT,要重点检查大字段写入逻辑 - 注意
owner:如果是SYSTEM或SYSAUX下的对象,别急着删,先确认是否属AWR、统计信息等系统组件 - Oracle 11g 及以上建议用
FETCH FIRST,避免ROWNUM 在并行查询下结果不准
结合 v$session 和 v$sql 追踪活跃写入会话
如果表空间仍在持续增长,说明有会话正在高频写入或创建对象。此时需锁定“正在干活”的SQL,而非历史最大对象。
运行以下关联查询,找出当前正在向目标表空间写入的活跃会话及其SQL:
SELECT s.sid, s.serial#, s.username, s.osuser, s.program,
q.sql_id, q.sql_text
FROM v$session s
JOIN v$transaction t ON s.saddr = t.ses_addr
JOIN v$sql q ON q.sql_id = s.sql_id
WHERE s.status = 'ACTIVE'
AND s.username IS NOT NULL
AND EXISTS (
SELECT 1 FROM dba_extents e
WHERE e.owner = s.username
AND e.file_id IN (
SELECT file_id FROM dba_data_files
WHERE tablespace_name = 'USERS' -- 替换为目标表空间
)
AND ROWNUM = 1
);
- 该查询依赖
dba_extents关联实际分配的文件,比单纯查sql_text更可靠 - 注意:
v$transaction只捕获有未提交事务的会话,对纯INSERT/UPDATE但已提交的场景不适用 - 若返回为空,说明增长可能来自批量作业(如ETL脚本),需结合
dba_hist_active_sess_history查最近1小时历史
警惕 UNDO 和 TEMP 表空间的“伪爆满”
ORA-01653 报错里写的表空间名,未必就是真正爆满的那个。例如:
- 报错说
unable to extend table SCOTT.EMP in tablespace USERS,但实际可能是UNDO表空间不足,导致事务无法回滚,进而阻塞新扩展 - 或
TEMP空间耗尽,使 CREATE INDEX、大型排序失败,临时段残留占位,间接拖慢空间回收
务必同步检查:
-- 检查UNDO使用率(高且持续上升=长事务未提交) SELECT tablespace_name, status, ROUND(sum(bytes)/1024/1024,2) mb FROM dba_undo_extents GROUP BY tablespace_name, status;
-- 检查TEMP当前活跃使用(非空闲空间) SELECT tablespace_name, used_blocks*8/1024 mb_used FROM v$temp_space_header;
-
dba_undo_extents中EXPIRED状态占比低、UNEXPIRED高,说明大量事务未提交或undo_retention设置过大 -
v$temp_space_header.used_blocks接近dba_temp_files.bytes,说明临时段未释放,需查v$sort_usage
别忽略自动扩展关闭和碎片化这两个“静默杀手”
即使 DBA_SEGMENTS 显示还有几GB空闲,也可能因碎片无法分配连续区而报 ORA-01653。常见于长期未维护的表空间。
- 先确认数据文件是否允许扩展:
SELECT file_name, autoextensible, maxbytes FROM dba_data_files WHERE tablespace_name = 'USERS';—— 若全是NO,加文件或开扩展是唯一解 - 检查碎片程度:
SELECT COUNT(*) chunks, MAX(bytes)/1024/1024 max_chunk_mb FROM dba_free_space WHERE tablespace_name = 'USERS';—— 若max_chunk_mb 且总空闲 > 100MB,说明严重碎片,需ALTER TABLESPACE ... COALESCE或重建 - 碎片修复后,立刻查
dba_extents确认最大连续区是否变大,否则操作无效
真正难处理的从来不是“空间不够”,而是“空间在那里,却用不上”。定位时优先看段分布和文件属性,SQL语句只是表象背后的触发器,不是根因本身。











