Autoallocate并非bug而是Oracle主动预分配策略:按extent数量阶梯式扩大分配单位(如9i中第16个extent起升至1MB),导致小表占用远超实际需求的空间,表现为dba_extents中大量大extent与实际数据量严重不匹配。
Autoallocate 为什么会“分配过快”又“看似浪费”
这不是 bug,是 oracle 在 autoallocate 模式下主动“抢跑”:它按段增长节奏预判后续空间需求,提前用更大的 extent(比如从 64kb 跳到 1mb),结果小表刚建好就占了远超所需的空间。常见现象包括:dba_extents 里看到大量 1mb 或 8mb 的 extent,但实际数据只占几 kb;dba_segments.bytes 远小于 dba_segments.blocks × 8192(假设块大小 8k)。
根本原因在于 Oracle 的自动策略不看当前实际用量,只看“已分配的 extent 数量”——例如 Oracle 9i 中第 16 个 extent 起就强制切到 1MB,哪怕前 15 个都只存了几十行记录。
- Oracle 10g+ 对此做了优化(首次 128 个
extent都是 8MB),但依然无法避免“小对象被大区绑架” -
AUTOALLOCATE不允许指定INITIAL或NEXT,你无法压制它的扩张冲动 - 频繁
INSERT ... SELECT+DROP小中间表时,AUTOALLOCATE容易在位图中留下大量 1MB 碎片空洞
Uniform Size 多大才不算“过大”或“过小”
选错 UNIFORM SIZE 比用错模式更危险。设成 1M 是文档默认值,但生产环境常踩两个坑:
- 设太小(如
128K)→ 大表(>1GB)会生成上千个extent,加重 LMT 位图维护开销,ALTER TABLE ... MOVE变慢 - 设太大(如
64M)→ 小表(extent,空间利用率跌到 1.5%,且无法被其他段复用 - 真实建议:先查历史最大中间表尺寸,取其 1.2 倍后向下取整到 2 的幂(如 512MB 表 → 用
UNIFORM SIZE 512M;200MB 表 → 用256M)
执行前务必确认:该表空间只放一类可预测尺寸的对象。混放小配置表和大分区表,UNIFORM 会迅速失控。
什么时候必须换 Autoallocate 为 Uniform
不是“性能差就换”,而是出现以下任一情况时,AUTOALLOCATE 已经成为瓶颈:
-
select count(*) from dba_extents where tablespace_name = 'TS_NAME'返回值 > 5000,且avg(blocks) - 批量作业(如 ETL)反复创建/删除固定大小的临时表(如总在 450±20MB 区间),此时
AUTOALLOCATE每次都分配 512MB 或 1GB 的extent,浪费可控但不可接受 - 使用
DBMS_SPACE.SPACE_USAGE发现某段的unformatted_blocks占比长期 > 30%,且full_blocks很低 → 典型“大区装小数据”症状
注意:切换需重建表空间,无法在线操作。迁移前用 expdp 导出再导入是最稳路径,别信“alter table move tablespace”的省事方案——它不重排 extent 分配逻辑。
Autoallocate 真的不能调?其实有隐式控制点
虽然文档说 AUTOALLOCATE 不受 STORAGE 子句影响,但 Oracle 在段创建瞬间仍会参考 INITIAL 参数做一次“截断选择”:
- 设
INITIAL 128K→ Oracle 会优先选 64Kextent,凑够 2 个完事,不会跳到 1MB - 设
INITIAL 2M→ 它会选 1MBextent,分配 2 个,跳过 64K 阶段 - 这个 trick 仅对首次分配有效,后续增长仍走标准规则(9i/10g 规则不同,务必查
v$version)
所以如果你有一批小而固定的日志表,建表时显式写 STORAGE(INITIAL 64K),能显著压低初始碎片。但这不是长久之计——长期看,这类表更适合挪进一个 UNIFORM SIZE 128K 的专用表空间。
最易被忽略的一点:AUTOALLOCATE 表空间一旦创建,allocation_type 就锁死,连 ALTER DATABASE 都不能改。判断失误的成本,是重建整个表空间及所有对象。


















