预分配extent仅在对象为普通堆表、段未碎片化、争用集中于hw锁且可预测峰值时临时缓解短时争用;对lob段、rac环境及已碎片化段基本无效。

预分配 EXTENT 不能消除高并发段扩展争用,只能绕过单次 HW 锁排队;对 LOB 段、RAC 环境、已碎片化段基本无效。
什么时候 ALLOCATE EXTENT 能临时起效
仅在以下条件同时满足时,ALTER TABLE t ALLOCATE EXTENT (SIZE 100M) 才可能缓解短时争用:
- 对象是普通堆表(非
LOBSEGMENT、非索引组织表) - 当前段尚未严重碎片化(即空闲空间仍较连续)
- 争用集中在 HW 锁(
enq: HW - contention),且 P3 指向段头块而非其他数据块 - 业务写入峰值可预测,能提前在低峰期执行预分配
执行后不会释放已有碎片,也不改变后续 DML 的空间分配路径——它只是“多搬几箱货到仓库门口”,没解决搬运工排队问题。
为什么对 LOB 段直接 ALLOCATE EXTENT 会失败
LOB 数据不直接挂在表段下,而是存于独立的 LOBSEGMENT,其段名由 Oracle 自动生成(如 SYS_LOB0000098765X$$)。直接对表执行 ALLOCATE EXTENT 不作用于 LOB 存储段。
必须分两步操作:
- 查真实 LOB 段名:
SELECT segment_name, tablespace_name FROM dba_lobs WHERE table_name = 'T' AND column_name = 'CONTENT' - 再对其预分配:
ALTER TABLE t MODIFY LOB(content) (ALLOCATE EXTENT (SIZE 50M))或直接ALTER TABLE <lob_segment_name> ALLOCATE EXTENT...</lob_segment_name>(需先确认段类型)
注意:若 LOB 列未随表分区,即使预分配,所有写入仍打在同一 LOB 段的 bitmap 块上,争用照旧。
RAC 环境下预分配的局限性
RAC 中 extent 分配不是单节点行为,仍需全局协调。执行 ALLOCATE EXTENT 会触发跨实例的 gc buffer busy acquire 和 enq: SQ - contention(序列锁),尤其当底层使用共享序列时。
更关键的是:HW 锁本身在 RAC 中就是全局资源,单节点预分配无法规避其他实例对同一段 HWM 推进的锁请求。常见错误是误以为“我在节点1预分配了,节点2就不用抢了”——实际节点2插入时仍要校验并可能等待 HW 锁。
真正有效的做法是让段天然分散:
- 对高频写入表强制分区(
RANGE或HASH,至少 4 个分区) - 确保 LOB 列启用
STORE AS SECUREFILE并随主表分区 - 禁用
FREELISTS,只用 ASSM,但必须配合分区——否则第一个 bitmap 块仍是热点
预分配大小怎么定才不白干
预分配太小(如 SIZE 1M)等于没做;太大(如 SIZE 1G)又浪费空间且可能触发表空间级争用。合理值应满足:
- ≥ 当前最大已分配
EXTENT的BYTES:SELECT DISTINCT bytes FROM dba_extents WHERE segment_name = 'T' ORDER BY bytes DESC FETCH FIRST 1 ROW ONLY - ≤ 表空间剩余空闲空间的 30%,避免触发自动扩展争用
- 避开系统默认的 autoallocate 增长节奏(如 64K→1M→8M),选中间档位(如 100M)减少后续自动分配频次
最易被忽略的一点:预分配不改变段的 INITIAL 和 NEXT 参数,下次自动扩展仍按原策略来。若没同步调整存储参数,几小时后争用重现。











