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:不重新导出,在目标库手动补缺失空表
-
在源库查询所有表名,导出表名清单:
--sql SPOOL D:\all_table.txt; SELECT TABLE_NAME FROM USER_TABLES; SPOOL OFF; -
在目标库对比,找出缺失表,手动执行建表语句重建空表;
-
再单独导入约束、索引、序列等对象。
四、最优规避方案:改用数据泵 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
五、常见踩坑补充
-
分配段时报表空间不足:先扩容用户默认表空间再执行;
-
NUM_ROWS统计不准:先执行表分析再筛选空表:--sql EXEC DBMS_STATS.GATHER_SCHEMA_STATS(OWNNAME=>'用户名'); -
分区空表:需要用
dbms_space_admin.materialize_deferred_segments给空分区分配段。