expdp导出数据时,ORA-31693,ORA-02354,ORA-01555错误问题处理
一、机器及数据库配置
OS:RHEL6.5
内核:2.6.32-431.el6.x86_64
CPU:4颗96c
内存:256G
数据版本:oracle 11.2.0.4 rac 双节点
数据文件存储:ASM
数据导出方式:expdp ... compression=all cluster=n parallel=12
二、报错信息
1)expdp日志报错信息
ORA-31693: Table data object "schema1"."table1" failed to load/unload and is being skipped due to error:
ORA-02354: error in exporting/importing data
ORA-01555: snapshot too old: rollback segment number 20 with name "_SYSSMU20_3347302954$" too small
......
2)实例上alter.log报错信息
Wed Aug 14 21:57:03 2019
ORA-01555 caused by SQL statement below (SQL ID: bcmcxyhhx3ns4, SCN: 0x09eb.de998b9e):
SELECT * FROM RELATIONAL("schema1"."table1")
......
可以看到,alter日志和expdp日志报错一致,是同一个问题。
三、解决思路
ORA-01555问题,一般是undo表空间不足,或undo_retention参数设置太小,导致导出大表时,之前的undo记录被覆盖
1)表上没有LOB字段
1.先检查undo表空间使用率
#表空间使用率查询SQL
SQL> SELECT UPPER(F.TABLESPACE_NAME) AS "表空间名",
D.TOT_GROOTTE_MB AS "表空间大小(M)",
D.TOT_GROOTTE_MB-F.TOTAL_BYTES AS "已使用空间(M)",
TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
F.TOTAL_BYTES AS "空闲空间(M)",
F.MAX_BYTES AS "最大块(M)"
FROM (SELECT TABLESPACE_NAME,
ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
FROM SYS.DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME) F,
(SELECT DD.TABLESPACE_NAME,
ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
FROM SYS.DBA_DATA_FILES DD
GROUP BY DD.TABLESPACE_NAME) D
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
ORDER BY 1;
2.检查undo_retention参数设置
SQL> show parameter undo_retention;
3.检查undo中最长查询时间
SQL> select max(maxquerylen) from v$undostat;
小结:
如果undo表空间使用率已满,扩展undo表空间。
根据undo中最长查询时间,设置undo_retention参数值。
2)表上有LOB字段
oracle的lob大字段有自己的retention参数,如果只调整undo_retention,而没有同步到lob大字段,该参数还是默认的900s,所以除了设置全局retention参数外,
还应设置lob字段的retention参数。
1.检查LOB字段retention
SQL> select table_name,column_name,pctversion,retention from dba_lobs where owner='SCHEMA1' and table_name='TABLE1';
或
SQL> select column_name, pctversion, retention from user_lobs where table_name='TABLE1'
注意:如果表是使用之前的pctversion,要同步修改为retention
2.修改LOB字段retention时间
SQL>ALTER TABLE schema1.table1 MODIFY LOB(lob_colume)(retention);
四、解决问题
1)检查表结构,确认表上是否有LOB字段
SQL> desc schema1.table1
Name Null? Type
----------------------------------------- -------- ----------------------------
POLICYNO NOT NULL VARCHAR2(30)
ENDORSEQNO NOT NULL VARCHAR2(3)
PLANCODE NOT NULL VARCHAR2(4)
RISKCODE NOT NULL VARCHAR2(4)
CLAUSECODE NOT NULL VARCHAR2(12)
LINENO NOT NULL NUMBER(20)
CLAUSECNAME VARCHAR2(255)
CLAUSECONTEXT VARCHAR2(2000)
TITLEIND NOT NULL VARCHAR2(1)
SERIALNO NOT NULL NUMBER(4,1)
READONLYIND NOT NULL VARCHAR2(1)
DISPLAYNO NUMBER(7,2)
FLAG VARCHAR2(2)
CREATED_BY VARCHAR2(100)
DATE_CREATED NOT NULL DATE
UPDATED_BY VARCHAR2(100)
DATE_UPDATED NOT NULL DATE
可见,表上没有LOB字段。
2)检查undo表空间使用率
可以看到undo表空间使用率并不高,节点1的使用率只有2%
UNDOTBS1 32867.98 663.04 2.02% 32204.94 3968
UNDOTBS2 25550 862.06 3.37% 24687.94 3968
3)检查undo_retention
SQL> show parameter undo_retention;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_retention integer 900
4)检查检查undo中最长查询时间
SQL> select max(maxquerylen) from v$undostat;
MAX(MAXQUERYLEN)
----------------
11972
11972s约3.5小时,数据库的undo_retention=900(默认),我们把保留时间设置为4小时(14400s)
5)设置undo_retention时间
alter system set undo_retention=14400 sid='*' scope=both;
五、最终效果
expdp导出数据正常,报错消失。
1)参数undo_retention时间
SQL> show parameter undo_retention;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_retention integer 14400
2)undo中最长查询时间,与之前没有变化
SQL> select max(maxquerylen) from v$undostat;
MAX(MAXQUERYLEN)
----------------
11972
3)undo表空间使用率,相比之前有所增加
UNDOTBS1 32867.98 2103.04 6.40% 30764.94 3968
UNDOTBS2 25550 1822.06 7.13% 23727.94 3968
六、总结
分析产生该错误的主要原因为回滚段设置太小,通常在UNDO回滚段中会保留数据库在某个时间点的数据,用来保证数据的一致性读。而在用户利用数据泵工具执行导出数据表操作时,又有其它用户对该表进行了修改,如果修改提交后UNDO中无足够空间,之前保存在UNDO中的数据资料就会被覆盖,从而依赖于这些数据资料的操作就无法获得一致性读,导致数据迁移过程产生以上报错。而且Oracle由参数undo_retention指定时间去释放UNDO回滚段,所以如果数据迁移时长超过undo_retention指定时间也会导致快照过旧的问题产生。
七、知识点
LOB字段的PCTVERSIOIN与RETENTION
1)老的方式:PCTVERSIOIN
这个参数关系到LOB数据的一致读,指的是表lob字段所在的表空间需要预留给lob的前映象使用的最大百分比,默认值是10。也就是说,只要使用不超过10%,LOB字段的前映像的数据是不会被覆盖的。
2) 新的方式(自动还原段管理使用):RETENTION
Oracle用UNDO_RETENTION参数来决定在数据库中保留多少已经提交的UNDO数据。这种方式LOB段跟普通段使用相同的过期策略。
计算业务高峰期每秒产生undo数据块的个数
SQL> select max(undoblks / ((end_time - begin_time)*24*3600)) from v$undostat;