不生效。Oracle的DEFERRED_SEGMENT_CREATION参数对分区表整体无效,建表时指定SEGMENT CREATION DEFERRED仍会为首个分区立即创建段;仅ALTER TABLE ADD PARTITION后且满足无数据、无统计信息等条件时可能延迟段创建。
Deferred Segment Creation 在分区表上到底生效不生效?
不生效。oracle 的 deferred_segment_creation 参数对**分区表整体无效**——哪怕你建表时显式指定 segment creation deferred,oracle 仍会为每个新定义的分区(尤其是第一个分区)立即创建段(segment),除非该分区是空的且通过 add partition 动态添加、且满足特定条件。
根本原因在于:分区表的元数据强依赖段存在性来维护分区边界和统计信息;延迟段只适用于“完全空的、无分区定义”的普通表。
- 常见错误现象:
CREATE TABLE t (...) PARTITION BY RANGE (c) (PARTITION p1 VALUES LESS THAN (100)) SEGMENT CREATION DEFERRED执行后立刻能在DBA_SEGMENTS中查到p1对应的段 - 唯一可能“延迟”的场景:用
ALTER TABLE ... ADD PARTITION新增一个分区,且该分区尚未插入任何数据、未收集统计信息、且表本身已有其他非空分区 —— 此时 Oracle 可能暂不分配物理段,但一旦执行INSERT、ANALYZE或甚至某些 DDL(如MOVE PARTITION),段立刻被强制创建 - 参数差异:
DEFERRED_SEGMENT_CREATION=TRUE对CREATE TABLE ... PARTITION BY ...语句无实际约束力;它只影响不含分区子句的普通表
如何验证某个分区是否真有段?
不能只看 DBA_TABLES 的 SEGMENT_CREATED 列——它对分区表始终返回 YES,不管底层有没有物理段。必须查分区级视图。
- 正确方式:
SELECT PARTITION_NAME, SEGMENT_CREATED FROM DBA_TAB_PARTITIONS WHERE TABLE_NAME = 'T' AND TABLE_OWNER = 'U' - 注意
SEGMENT_CREATED = 'NO'是罕见状态,仅出现在动态新增分区后、且尚未触发任何段分配操作时;稍后执行SELECT COUNT(*) FROM T PARTITION (p2)就会让它变成YES - 容易踩的坑:用
DBA_SEGMENTS查分区段时,SEGMENT_NAME是表名,PARTITION_NAME才是分区名;漏查PARTITION_NAME会导致误判
为什么 ALTER TABLE ... ADD PARTITION 有时不建段,有时又建?
关键不在语法,而在当前分区键值范围是否与已有数据冲突、以及优化器是否需要立即定位该分区。
- 不建段的典型路径:
ALTER TABLE t ADD PARTITION p3 VALUES LESS THAN (300),此时若表中最大已存在分区是p2 VALUES LESS THAN (200),且全表无数据落入[200, 300)区间,Oracle 可延迟段创建 - 立刻建段的触发点:
INSERT /*+ APPEND */ INTO t VALUES (250, ...)(直接写入新分区)、DBMS_STATS.GATHER_TABLE_STATS(即使指定partname => 'p3')、ALTER TABLE t MOVE PARTITION p3 - 性能影响:延迟段看似省空间,但首次写入时需同步完成段分配 + 数据写入 + 索引更新,可能造成单次 INSERT 延迟突增;而预建段把开销摊到 DDL 阶段
想彻底避免延迟段干扰分区管理,怎么办?
主动放弃幻想,按确定性方式建模。
- 建表时明确指定
SEGMENT CREATION IMMEDIATE(虽然对分区表是冗余的,但可避免后续误读) - 新增分区后,立刻执行一条空插入再回滚:
INSERT INTO t PARTITION (p3) SELECT * FROM t WHERE 1=0; ROLLBACK;—— 这会强制创建段,且不污染数据 - 监控脚本里别依赖
SEGMENT_CREATED = 'NO'做自动化判断;改用SELECT COUNT(*) FROM DBA_EXTENTS WHERE SEGMENT_NAME = 'T' AND PARTITION_NAME = 'p3'更可靠 - 容易被忽略的点:
TRUNCATE PARTITION不会删段,只会清数据;DROP PARTITION才真正释放段——但后者会重编译全局索引,代价更高










