Oracle 11g 延迟段创建问题解决方案(全库导出恢复缺空表)

Oracle 11g 延迟段创建问题解决方案

一、根本原因

用的是 Oracle 11g ,默认开启参数 deferred_segment_creation=TRUE(段延迟创建): 新建空表没有插入数据时,Oracle不会给表分配物理段(segment) ,传统 exp 工具只能导出分配过段的表,没分配段的空表不会写入 DMP 文件,所以导入时这些表直接缺失。

可以用这条 SQL 验证源库哪些表没分配段:

复制代码
--sql
SELECT TABLE_NAME,SEGMENT_CREATED FROM USER_TABLES WHERE SEGMENT_CREATED='NO';

二、方案 1:重新完整导出(推荐,一次性解决)

步骤 1:源库给所有空表手动分配段

方式 A:直接生成批量执行语句

复制代码
--sql
SELECT 'ALTER TABLE '||TABLE_NAME||' ALLOCATE EXTENT;' FROM USER_TABLES WHERE SEGMENT_CREATED='NO';

把查询结果里所有ALTER TABLE语句复制执行,所有空表就会分配物理段,就能被 exp 正常导出。

方式 B:一键导出 SQL 脚本批量执行

复制代码
--sql
SET HEADING OFF; 
SET FEEDBACK OFF; 
SPOOL D:\alloc_table.sql; 

SELECT 'ALTER TABLE '||TABLE_NAME||' ALLOCATE EXTENT;' FROM USER_TABLES WHERE SEGMENT_CREATED='NO'; 

SPOOL OFF; 
SET HEADING ON; 
SET FEEDBACK ON;

在 SQLPLUS 执行 @D:\alloc_table.sql 批量执行分配语句。

步骤 2:重新 exp 导出 DMP

复制代码
--cmd
exp 用户名/密码@实例 FILE=备份.dmp OWNER=用户名 LOG=导出日志.log

这次所有空表都会被写入 DMP,导入就能全部恢复。

可选:永久关闭延迟段创建(后续新建表不会再漏)

复制代码
--系统级修改,需DBA权限 
ALTER SYSTEM SET deferred_segment_creation=FALSE SCOPE=SPFILE; 
--重启数据库生效 
SHUTDOWN IMMEDIATE; 
STARTUP;

注意:该参数只对之后新建的表生效,历史已存在的空表还是需要手动分配段。

三、方案 2:不重新导出,在目标库手动补缺失空表

  1. 源库查询所有表名,导出表名清单:

    复制代码
    --sql
    SPOOL D:\all_table.txt; 
    SELECT TABLE_NAME FROM USER_TABLES; 
    SPOOL OFF;
  2. 在目标库对比,找出缺失表,手动执行建表语句重建空表;

  3. 再单独导入约束、索引、序列等对象。

四、最优规避方案:改用数据泵 expdp(11g 推荐)

expdp 不受延迟段创建影响,默认会导出所有空表元数据,不会丢失空表,不需要提前分配段:

复制代码
--sql
--源库先创建逻辑目录(DBA执行) 
CREATE OR REPLACE DIRECTORY DUMP_DIR AS 'D:\oracle_bak'; 
GRANT READ,WRITE ON DIRECTORY DUMP_DIR TO 你的用户;

--cmd
expdp 用户名/密码@实例 DIRECTORY=DUMP_DIR DUMPFILE=备份.dmp SCHEMAS=用户名 LOGFILE=expdp.log CONTENT=ALL

导入命令:

复制代码
--cmd
impdp 用户名/密码@实例 DIRECTORY=DUMP_DIR DUMPFILE=备份.dmp SCHEMAS=用户名 LOGFILE=impdp.log

五、常见踩坑补充

  1. 分配段时报表空间不足:先扩容用户默认表空间再执行;

  2. NUM_ROWS统计不准:先执行表分析再筛选空表:

    复制代码
    --sql
    EXEC DBMS_STATS.GATHER_SCHEMA_STATS(OWNNAME=>'用户名');
  3. 分区空表:需要用 dbms_space_admin.materialize_deferred_segments 给空分区分配段。