UNIFORM SIZE 不能解决碎片问题,因其仅保证新分配区大小一致,无法防止删除操作后产生离散空闲区,且 Oracle 不自动合并空闲区,尤其在 ASSM 下位图只记录区可用性而非连续性。
为什么 UNIFORM SIZE 不能解决碎片问题
很多人以为只要建表空间时指定 uniform size,就能彻底避免碎片——这是个常见误解。uniform 只控制新分配的 extent 大小一致,但不阻止已分配的 extent 被反复 delete / truncate / drop 后留下空洞。oracle 不会自动合并相邻空闲 extent,尤其在 assm(自动段空间管理)下,位图块记录的是“哪个区可用”,而不是“哪段连续空间可用”。所以即使所有 extent 都是 1mb,空闲区仍可能是离散的。
实操建议:
- 检查真实碎片程度,别只看
DBA_TABLESPACES的ALLOCATION_TYPE:用SELECT * FROM DBA_EXTENTS WHERE TABLESPACE_NAME = 'XXX' ORDER BY BLOCK_ID观察BLOCK_ID是否跳跃 -
UNIFORM SIZE适合写入模式稳定、对象生命周期相近的场景(如日志归档表空间),不适合 OLTP 主业务表空间 - 如果已经用了
UNIFORM SIZE却仍有性能抖动,大概率是高水位线(HWM)卡住 + 空闲区不连续,此时重建比调参更有效
真正有效的碎片清理路径:从 ALTER TABLE ... SHRINK SPACE 到表空间重建
碎片影响的是段(segment)级空间利用率,不是表空间整体。所以得先治段,再看表空间。
实操建议:
- 对单个大表,优先跑
ALTER TABLE t SHRINK SPACE COMPACT(需启用行移动:ALTER TABLE t ENABLE ROW MOVEMENT),它重排行并降低 HWM,但不释放空间给表空间 - 加
CASCADE参数才能同步收缩索引,否则索引可能变无效;注意该操作会持SS锁,阻塞 DML - 若表无主键/唯一约束,或含
LOB字段,SHRINK可能失败,此时改用CREATE TABLE AS SELECT+ 重命名 + 约束重建 - 最后一步才是释放空间给表空间:执行
ALTER TABLESPACE xxx COALESCE(仅对DICTIONARY-MANAGED有效)或直接DROP TABLESPACE xxx INCLUDING CONTENTS AND DATAFILES(重建前提前导出元数据)
EXTENT MANAGEMENT LOCAL AUTOALLOCATE vs UNIFORM:选哪个更抗碎片?
答案是:AUTOALLOCATE 在大多数场景下反而更少产生人为碎片。Oracle 会按需分配 64KB → 1MB → 8MB 的 Extent,小对象用小区,大对象用大区,天然适配数据增长节奏;而硬设 UNIFORM SIZE 容易导致“小表占大区”或“大表被迫切碎成太多小区”。
实操建议:
- 新建表空间默认用
EXTENT MANAGEMENT LOCAL AUTOALLOCATE,除非有明确压测证明 uniform 更稳(比如某 ETL 批处理固定生成 500MB 中间表) -
AUTOALLOCATE下的碎片更多来自逻辑删除而非分配策略,所以重点应放在定期SHRINK或分区表滚动清理上 - 监控
DBA_SEGMENTS的BYTES和BLOCKS差值,若长期存在大量未使用 block(比如BLOCKS × 8192 - BYTES > 100MB),说明 HWM 没回落,不是 extent 分配问题
容易被忽略的底层限制:SEGMENT SPACE MANAGEMENT 和块头开销
即使 Extent 连续、HWM 降到底,实际可用空间仍可能远低于预期——因为每个数据块头部要预留空间存 ITL(interested transaction list)和行目录,且 SEGMENT SPACE MANAGEMENT AUTO(即 ASSM)用位图管理空闲块,本身就有约 1–2% 的元数据开销。
实操建议:
- 查真实空闲率别信
FREE_SPACE,用SELECT SUM(bytes)/1024/1024 FROM dba_free_space WHERE tablespace_name='XXX'对比DBA_DATA_FILES总大小 - 高并发 insert 场景下,ITL 争用会导致块“假满”,此时调大
INITRANS比调 Extent 更管用 - 如果表空间长期空闲率
且无法通过 SHRINK 提升,基本可以判定是设计问题(如过早预分配了 100GB 文件却只存了 5GB 数据),删文件比调参数实在
碎片不是配置项开关能一键关掉的事,它是数据生命周期、DML 模式、存储参数三者咬合的结果。最常被跳过的动作,其实是定期看 DBA_HIST_SEG_STAT 里各段的 LOGICAL_READS 和 PHYSICAL_WRITES 变化趋势——那里藏着比 UNIFORM SIZE 更真实的碎片信号。










