ora-01653/ora-01658报错本质是空闲空间不连续,无法分配所需extent:dba_free_space总和虽大,但最大连续块(max(bytes))小于请求大小,且行数>200即碎片严重;assm下coalesce无效,应依碎片程度选shrink space、move或truncate,并及时更新统计信息。
oracle表空间明明有free space,却报 ora-01653 或 ora-01658,根本不是没空间,而是碎片太碎、空闲块不连续,导致无法分配一个完整的新extent。
为什么dba_free_space显示有空闲,但建表/插入仍失败
Oracle分配空间以Extent为单位(比如 64KB、1MB),不是按字节拼凑。即使dba_free_space总和有 2GB 空闲,但如果这些空闲被切成几十个几十KB的小块,就无法满足一个需要 1MB Extent 的操作。
-
dba_free_space每行代表一段连续的空闲块;行数越多,说明碎片越严重 - 传统字典管理表空间(DMT)下,碎片超过 500 行基本可判定需整理
- 自动段空间管理(ASSM)虽缓解了部分问题,但频繁 DELETE + INSERT 仍会导致位图标记混乱,新数据倾向写入新区而非复用旧块
- 执行
SELECT tablespace_name, COUNT(*) FROM dba_free_space GROUP BY tablespace_name,若某表空间返回值 > 200,就要警惕
如何快速确认是碎片导致的“假性不足”
先排除真容量不足,再聚焦碎片:
- 查数据文件是否已到
maxsize:运行SELECT file_name, autoextensible, maxbytes FROM dba_data_files WHERE tablespace_name = 'YOUR_TS',若autoextensible = 'NO'且bytes = maxbytes,优先扩容 - 查最大连续空闲块:
SELECT MAX(bytes)/1024/1024 AS max_free_mb FROM dba_free_space WHERE tablespace_name = 'YOUR_TS'—— 如果这个值远小于你期望分配的Extent大小(如建索引要 8MB,但结果只有 0.5MB),就是碎片卡住了 - 对比段占用与实际数据量:对大表执行
SELECT segment_name, bytes/1024/1024, blocks FROM dba_segments WHERE tablespace_name = 'YOUR_TS' ORDER BY bytes DESC,再查该表行数和平均行长,若blocks × 8192 ≫ 行数 × avg_row_len,大概率存在高水位线(HWM)和内部碎片
ALTER TABLESPACE ... COALESCE 什么时候有用、什么时候没用
这个命令只对字典管理表空间(DMT)有效,作用是合并相邻的空闲Extent;在 ASSM 表空间中执行无任何效果,也不会报错 —— 这是很多人踩坑的地方。
- 适用前提:表空间是 DMT(
extent_management = 'DICTIONARY'),且空闲Extent物理相邻 - 执行后仍需检查
dba_free_space行数是否下降;若没降,说明空闲块本身就不邻接,COALESCE无力回天 - ASSM 表空间请直接跳过此步,改用
SHRINK SPACE或MOVE - 注意:该操作不锁表,但仅作用于当前表空间,不能跨数据文件
真正能释放连续空间的操作顺序(按影响程度由小到大)
别一上来就 MOVE 表,先看业务容忍度:
- 轻度碎片(HWM偏高、块内空闲多):
ALTER TABLE t ENABLE ROW MOVEMENT; ALTER TABLE t SHRINK SPACE COMPACT;—— 在线、低锁,但要求表有主键或启用行移动,且不会降低HWM - 中度碎片(需重置HWM):
ALTER TABLE t MOVE TABLESPACE tbs_name;—— 会锁表,重建段,释放HWM以下所有空间;之后必须重建索引(ALTER INDEX idx REBUILD) - 重度碎片+多对象混杂:收缩整个表空间不现实,应定位TOP消耗者(用
dba_segments排序),逐个处理;若某张表占 80% 空间且长期只删不插,直接TRUNCATE比DELETE干净得多 - 永远别忽略统计信息:任何
MOVE或SHRINK后,立即执行DBMS_STATS.GATHER_TABLE_STATS,否则执行计划可能劣化
碎片整理不是“一键清理”,关键在判断空闲是否连续、Extent是否可分配、操作是否在线。很多 DBA 卡在 COALESCE 无效却反复执行,其实是表空间类型不对;更多时候,问题不在“有没有空”,而在“能不能凑出一块够大的”。











