ORA-01628报错本质是undo段extents耗尽(达32765上限),非磁盘空间不足;根源在于undo表空间碎片化或小事务泛滥导致无法分配新extent,需先查活跃undo段extent使用率,再定位会话、清理碎片并调优UNDO_RETENTION。

ORA-01628报错前最该查的不是空间,而是段的EXTENTS使用率
Oracle段(包括undo段、表、索引等)的MAX_EXTENTS有硬上限(如32765),一旦EXTENTS接近该值,即使表空间还有空闲空间,也会触发ORA-01628等错误。关键不是“有没有空间”,而是“能不能再分配新extent”。
查所有段的EXTENTS使用率(含undo段)
用这个SQL快速识别哪些段已逼近MAX_EXTENTS上限:
SELECT segment_name, segment_type, tablespace_name, extents, max_extents, ROUND((extents / NULLIF(max_extents, 0)) * 100, 2) AS percent_used FROM dba_segments WHERE max_extents != 0 AND (extents / NULLIF(max_extents, 0)) >= 0.95 ORDER BY percent_used DESC;
-
NULLIF(max_extents, 0)防止除零错误;max_extents = 0通常表示UNLIMITED,但实际仍受底层限制(如32765) - 结果中
segment_type = 'ROLLBACK'或'UNDO'的条目要优先处理——它们是ORA-01628的直接诱因 - 注意
segment_name是否含_SYSSMU或RBS_前缀,这是Oracle自动管理undo段的典型命名
专查活跃undo段的extent分布
ORA-01628往往卡在某个ACTIVE undo段上,只看dba_segments不够,必须结合事务状态:
SELECT segment_name, status, COUNT(*) extent_count
FROM dba_undo_extents
WHERE status IN ('ACTIVE', 'UNEXPIRED')
GROUP BY segment_name, status
HAVING COUNT(*) > 32000
ORDER BY extent_count DESC;- 若某
segment_name的extent_count超过32000且status = 'ACTIVE',基本就是它堵住了 - 不要忽略
status = 'UNEXPIRED'的段——如果UNDO_RETENTION设得过大,这些段也无法被重用 - 查出段名后,用
v$rollname和v$transaction关联定位具体会话:SELECT sid, serial#, username FROM gv$session WHERE saddr IN (SELECT ses_addr FROM gv$transaction WHERE xidusn = &usn);
为什么不能只看DBA_FREE_SPACE?
很多人查dba_free_space发现还有几GB空闲,就认为“空间够”,结果仍报ORA-01628——因为问题不在总空闲量,而在表空间碎片化导致无法分配连续extent。
-
dba_free_space显示的是空闲块大小,不是连续extent能力 - 一个undo段申请新extent时,需要满足
NEXT_EXTENT大小的连续空闲区;若最大空闲块(BIG_CHUNK)小于NEXT_EXTENT,就分配失败 - 验证方法:运行
SELECT tablespace_name, MAX(bytes) big_chunk FROM dba_free_space GROUP BY tablespace_name;,再对比对应段的NEXT_EXTENT值 - 常见陷阱:
ALTER DATABASE DATAFILE ... AUTOEXTEND ON能扩容文件,但无法解决已有碎片
真正危险的不是EXTENTS总数高,而是活跃事务长期不提交、或UNDO_RETENTION远高于实际需求,导致undo段无法shrink——这点比参数调优更难监控,也最容易被忽略。


















