• Oracle事务槽wrap#上限问题


    问题背景:

            近期遇到了一个Oracle回滚段事务ID达到上限的问题,应用前台语句操作失败,出现ORA-01558: out of transaction ID's in rollback segment _SYSSMU10_4119033733$报错。

    问题分析:

            第一次遇到该报错,先到Oracle mos上查了一下ORA-01558报错的相关资料,找到了一个比较接近的案例,MOS ID:Bug 19700135 - ORA-600 [4187] when the undo segment wrap# is close to the max value of 0xffffffff (Doc ID 19700135.8),根据文章的描述,报错产生的原因是由于回滚段里面的事务槽由于事务的频繁申请,导致wrap#达到上限值0xffffffff(4294967295),致使事务申请失败,事务槽每分配给一个事务,wrap#就会递增,每次的递增值并不固定,但单次递增值不超过16。

            文档还给出了一条查询语句,用户确认当前回滚段是否出现wrap#达到了上限值的问题,通过查询undo基表x$ktue([K]ernel [T]ransaction [U]ndo transaction [E]ntry),找出wrap#在[-429496730,0]区间的回滚段

    1. select b.segment_name, b.tablespace_name
    2. ,a.ktuxeusn "Undo Segment Number"
    3. ,a.ktuxeslt "Slot"
    4. ,a.ktuxesqn "Wrap#"
    5. from x$ktuxe a, dba_rollback_segs b
    6. where a.ktuxesqn > -429496730 and a.ktuxesqn < 0
    7. and a.ktuxeusn = b.segment_id;

            在报错的数据库执行该查询语句,可以看到查询出来回滚段的确为报错回滚段_SYSSMU10_4119033733$,但这里为啥使用这个范围条件[-429496730,0]进行查询,包括查出来wrap#的数量含义,哪个事务槽有问题,文章并没有进行详细说明,为此,我对回滚段的wrap#上限值进行了研究测试。

    回滚段事务槽warp#上限研究测试:

            我们以UNDOTBS1表空间里面的一个回滚段_SYSSMU3_2471395754作为研究测试对象,dump出了回滚段的头块。

    1. ---使用dump undo header
    2. alter system dump undo header '_SYSSMU3_2471395754$';
    3. ---也可以通过dba_segments查出回滚段的头块ID,再通过dump datafile方式
    4. alter system dump datafile 3 block 128;

           分析dump的回滚段头信息,单个回滚段里面34个事务槽,从0开始,每一个事务槽都有各自对应的wrap#大小,这里我们将研究测试的对象缩小到0号槽0x00,当前的wrap#为0x0fae,转成10进制为4014。

            再通过x$ktue查询该回滚段的wrap信息,可以看到列ktuxeslt和ktuxesqn分别对应事务槽slot和wrap#,查到到数值为0和4014,与dump回滚段头信息一致。

    1. select b.segment_name, b.tablespace_name
    2. ,a.ktuxeusn "Undo Segment Number"
    3. ,a.ktuxeslt "Slot"
    4. ,a.ktuxesqn "Wrap#"
    5. from x$ktuxe a, dba_rollback_segs b
    6. where a.ktuxeusn = b.segment_id and b.segment_name='_SYSSMU3_2471395754$';

            使用bbed打开回滚段所在的块,通过find命令查询事务槽的offset,需要注意的是对于Linux,由于字节序是little-endian,所以要低位开始读取,比如dump文件里面的wrap#为00000fae,在bbed显示的顺序为ae0f0000,所以查找wrap#的位置通过find /x ae0f,查到0号槽的wrap#的offset为6200-6203。

            通过bbed修改0号槽的wrap#的offset为上限值ffffffff,模拟wrap#达到上限值。

            再次查看x$ktue里面回滚段0号槽的wrap#大小,可以看到wrap#显示的值为-1。

           通过set transaction user rollback segment方式测试事务指定使用wrap#为-1槽所在的回滚段,看看会出现什么样的问题。

    1. begin
    2. for i in 1..100000 loop
    3. set transaction USE ROLLBACK SEGMENT "_SYSSMU3_2471395754$";
    4. delete from test.test where rownum<2;
    5. commit;
    6. end loop;
    7. end;
    8. /

            可以看到操作会话直接异常断开ORA-03113,并且后台日志出现大量的ORA-00600: internal error code, arguments: [4194], [], [], [], [], [], [], [], [], [], [], []报错,语句无法正常执行。

            通过bbed重新修改wrap#为fffffffa(4294967290)离上限值只差距5。

            再次查看x$ktue里面回滚段0号槽的wrap#大小,可以看到wrap#显示的值为-6。

            再次通过set transaction user rollback segment测试事务指定使用wrap#为-6的回滚段,可以看到这一次复现了ORA-01558: out of transaction ID's in rollback segment _SYSSMU3_2471395754$的报错。

           再次查看x$ktue里面回滚段0号槽的wrap#大小值为-2,没有再变化,接近最大值ffffffff。

            修改wrap#为最大值的一半:7fffffff,可以看到x$ktue里面显示的值为2147483647。

            修改wrap#为最大值的一半加1:80000000,可以看到x$ktue里面显示的值为-2147483647。所以,x$ktue里面显示的wrap#的值范围将ffffffff且为了两段,第一段[0,2147483647],第二段[-2147483647,-1]。wrap#越接近-1的代表该事务槽slot接近上限。

            这时候我们再看回mos文档给的查询语句,a.ktuxesqn > -429496730 and a.ktuxesqn < 0查询条件的含义就是查询wrap#的值范围接近ffffffff上限的事务槽

            而之前问题查到的结果回滚段_SYSSMU10_4119033733$事务槽里面slot 14的wrap#为-17,接近上限值-1,就是导致出现ORA-01558: out of transaction ID's in rollback segment _SYSSMU10_4119033733$报错的原因。

    问题修复:

            对于回滚段事务槽达到上限的,可以通过重建undo表空间的方法进行修复。

            注:重启数据库,不会导致回滚段wrap#清空。

            重建undo表空间的操作步骤。

    1. --创建新的undo表空间
    2. SQL> create undo tablespace <New Undo Tablespace name> datafile size <new size>;
    3. --设置当前的默认表空间为新undo表空间
    4. SQL> alter system set undo_tablespace=<New Undo Tablespace name>;
    5. --查看旧undo表空间是否存在online的回滚段,即使切换了默认的undo表空间,已经被事务分配使用的旧undo回滚段依然在使用,直到事务提交之后才释放
    6. SQL> select status,segment_name from dba_rollback_segs where status not in ('OFFLINE') and tablespace_name=<undo tablespace to be dropped>;
    7. --需要等待旧undo表空间没有online的回滚段才能drop 旧的undo表空间
    8. SQL>Drop tablespace <tablespace_name> including contents and datafiles;

  • 相关阅读:
    如何创建网站才能满足用户需求?
    mac虚拟机安装配置qt遇到的坑
    Spring Bean的作用域
    C语言进阶C++知识点补充(一)
    html静态商城网页制作 基于HTML+CSS+JavaScript在线服装商城店铺商城设计毕业论文源码
    WordPress初学者入门教程-附录一搜索引擎优化(SEO)
    SeAndroid 安全策略机制
    Linux常用命令——clear命令
    浅析Java反射机制
    构建“产业大脑”,以“数字化”提升园区运营管理及服务能力!
  • 原文地址:https://blog.csdn.net/sinat_36757755/article/details/136713725