ORA-01658报错主因是表空间缺乏足够大的连续空闲区,而非磁盘空间不足;需用DBA_FREE_SPACE查最大连续块并对比对象INITIAL大小。
ORA-01658报错时,先确认是不是真的没空间了
ora-01658本质不是“磁盘满了”,而是数据库在当前表空间里找不到连续的空闲区(extent)来满足新段(比如表或索引)的初始分配请求。常见错觉是看dba_free_space总和很大,就以为够用——其实碎片化严重时,最大连续块可能远小于你要建的段的initial大小。
实操建议:
- 查最大可用连续块:
SELECT TABLESPACE_NAME, MAX(BYTES) / 1024 / 1024 AS "MAX_MB" FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME;
- 对比你要创建的对象的初始大小(如
CREATE TABLE ... STORAGE(INITIAL 10M)),如果MAX_MB - 别只看
DBA_DATA_FILES的BYTES——那是文件总大小,不反映内部碎片
ALTER TABLESPACE … ADD DATAFILE 是最直接的绕过方式
加新数据文件不依赖现有碎片整理,只要磁盘有空间、用户有ALTER TABLESPACE权限,就能立刻缓解。但要注意路径、大小、自动扩展是否合理,否则下次还崩。
实操建议:
- 加文件前先确认表空间不是
READ ONLY:SELECT STATUS FROM DBA_TABLESPACES WHERE TABLESPACE_NAME = 'USERS';
- 推荐带
AUTOEXTEND ON NEXT 100M MAXSIZE 32G,避免频繁手工扩容 - 路径必须是数据库能写的目录,且注意ASM vs 文件系统路径写法差异(如
'+DATA'vs'/u01/oradata/db/users02.dbf') - 加完立刻执行
ALTER SYSTEM CHECKPOINT,确保控制文件同步,避免某些老版本Oracle误判空间
DBA_SEGMENTS + DBA_EXTENTS 能帮你定位“谁占着大块却不释放”
有些对象长期存在但几乎不用(比如归档表、测试表),却占着几十个连续区;或者LOB段默认PCTVERSION导致旧版本数据滞留。它们不显眼,却是碎片元凶。
实操建议:
- 找大而闲的段:
SELECT SEGMENT_NAME, SEGMENT_TYPE, BYTES/1024/1024 MB FROM DBA_SEGMENTS WHERE TABLESPACE_NAME = 'USERS' ORDER BY BYTES DESC FETCH FIRST 10 ROWS ONLY;
- 查某表的区分布密度:
SELECT COUNT(*) EXTENT_COUNT, MAX(BLOCK_ID)-MIN(BLOCK_ID) GAP_SPAN FROM DBA_EXTENTS WHERE SEGMENT_NAME = 'BIG_TABLE';
如果GAP_SPAN远大于EXTENT_COUNT * (block_size * blocks_per_extent),说明它内部也碎 - 临时表(
GLOBAL TEMPORARY TABLE)不会造成永久碎片,但ON COMMIT PRESERVE ROWS的会,检查DBA_OBJECTS.OBJECT_TYPE是否含TEMPORARY
COALESCE 表空间只能合并相邻空闲区,不能解决跨文件碎片
ALTER TABLESPACE ... COALESCE只对单个数据文件内、地址连续的空闲区有效。如果空闲块分散在不同数据文件里,它完全没用——这也是为什么加文件比整理更常用。
实操建议:
- 只对本地管理(
EXTENT MANAGEMENT LOCAL)、且使用UNIFORM SIZE的表空间谨慎尝试;AUTOALLOCATE下效果有限 - 执行前停业务或选低峰期,因为会持
SS锁,阻塞DML - 执行后立刻查
DBA_FREE_SPACE,如果COUNT(*)变少、MAX(BYTES)明显增大,说明成功;否则基本白干 - 别对SYSTEM、SYSAUX表空间用这个命令——风险高,收益极低
真正麻烦的是那种既有多个小数据文件、又混着LOB和INDEX高水位的对象。这时候COALESCE和ADD DATAFILE都只是止痛药,重建表空间才是根治,但得停应用、导出导入——多数人卡在这一步,不是不会做,是不敢动。










