UNDO相关问题总结(二)

本文总结了单个session占用大量undo导致数据库性能下降的问题。详细分析了问题的现象、原因及解决方法,并提供了几种应对策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一次主题为单个session占用大量undo,导致数据库性能急剧下降的问题总结。关于“undo表空间不足的问题”详见我上一篇总结。
问题现象
  • 数据库表现为“latch: undo global data”或者“wait for a undo record”等其它undo相关的等待事件
  • CPU资源急剧上升,可能达到100%
  • 业务运行缓慢
问题原因
  • session A在事务中对某张表(表T)进行DML操作,导致这张表上的回滚信息(前映像数据)超过一定阀值(一般100M以上,高并发下可能50M就算大量undo占用)。同一时刻(此时SESSION A的事务还未commit),大量并发连接(session B,C,D......等等)需要访问表T(访问的表数据块包含被session A修改的快),这种情况下由于需要完成读一致性要求,其它并发session 需要读取对应的回滚段构造CR块,此时SQL语句的执行效率会立马下降,数据库表现为“latch: undo global data”或者“wait for a undo record”等其它undo相关的等待事件,CPU资源急剧上升,可能达到100%,业务基本无法响应
引申现象
  1. 数据库中出现大量latch: undo global data”或者“wait for a undo record”相关的等待,但在当前实例中查询每个session的undo使用情况时,未发现有某个session占用大量undo。这种情况可能是由于其它实例的某个session使用大量undo导致,因此,需要所有实例上进行查询。
  2. 数据库中出现大量latch: undo global data”或者“wait for a undo record”相关的等待,但是在数据库的所有实例上查询,未发现有某个session占用大量undo,这种情况可能是由于占用大量undo的session事务已经commit,但是SQL语句效率下降的时间点是发生在事务未commit的时间段,主机cpu资源100%,由于排队效应,数据库整体运行效率低效,即使导致产生问题的事务提交完毕后,整个数据库也无法马上恢复正常,需要等待一段时间才能恢复正常(等待的时间未知,某些重要的系统,可能无法接受长时间的等待)
解决方法(仅供参考)
  1. 查询数据库所有实例中每个session的undo使用情况(也可以首先整体查询一下undo表空间的整体使用情况),具体SQL语句详见我上一篇博客“UNDO相关问题总结(一)”
  2. 如果查询结果中未发现有session正在占用大量undo,如上“引申现象中的2”部分,说明造成问题的session已经commit,可以等待一段时间,数据库会慢慢恢复正常。如果无法接受等待,可以考虑kill掉undo相关等待的连接,释放CPU资源。
  3. 如果查询结果中发现有session使用了大量undo(具体多少得看业务并发量,一般100M以上),首先得判断session当前正在进行的事务完成进度。如果即将完成,可以考虑等待事务完成提交后,数据库慢慢恢复正常,见步骤2。如果事务完成进度小于60%,可以考虑kill掉该session。判断事务完成进度的可以根据步骤1查询结构中的machine,program,module等信息定位具体的连接信息,然后询问开发人员、语句执行人员(如果该语句为人为执行)、查询v$session_longops也能有帮助。
  4. kill掉使用大量undo的连接后,由于回滚kill掉的事务需要时间(特别是问题发生后,CPU资源100%,数据库的任何操作都会特别缓慢,平时5分钟能完成的回滚,可能在问题时间段1个小时都无法完成),数据库性能恶劣的问题会持续很长一段时间,业务也极有可能根本不能接受这么长时间的无法响应。因此,后续解决问题的关键转化为怎么让事务回滚的更快。
  5. 评估回滚事务的完成进度,如下语句:
select usn, state, undoblockstotal "Total", undoblocksdone "Done", undoblockstotal-undoblocksdone "ToDo",
         decode(cputime,0,'unknown',sysdate+(((undoblockstotal-undoblocksdone) / (undoblocksdone / cputime)) / 86400)) "Estimated time to complete" 
  from v$fast_start_transactions; 
     过一段时间间隔后,再次使用上面的语句查询事务的回滚进度,可以预估完成回滚大概时间。
也可以使用如下语句查询回滚进度:
declare
l_start number;
l_end    number;
begin
  select ktuxesiz into l_start from x$ktuxe where  KTUXEUSN=194 and KTUXESLT=17; 
  dbms_lock.sleep(60);
  select ktuxesiz into l_end from x$ktuxe where  KTUXEUSN=194 and KTUXESLT=17;
  dbms_output.put_line('time est Day:'|| round(l_end/(l_start -l_end)/60/24,2));
end;
/

加快事务回滚的解决方法,可划分为三类(仅供参考)
数据库可以重启,可以考虑的解决办法
  1. 设置回滚并行度为HIGH
  2. 增加_cleanup_rollback_entries参数值(默认为100)
  3. 重启数据库,回滚完成后,开放给业务使用。
可以停止相关应用,可以考虑的解决办法
  1. 停止相关应用(涉及到这种表的查询),停止应用后,如果连接未断开,需要kill掉这些连接。
  2. 设置回滚并行度为HIGH(可能smon已经在回滚,无法调整并行度,此时需要先禁用smon回滚,然后设置并行度,再恢复smon回滚)
  3. 回滚完成后,启动相关应用
数据库不能重启,相关应用也不能停止,可以考虑的解决办法
  1. rename正在回滚的表,同时新建一张空表替换(注意考虑索引,外键,依赖性等等),将那些等待的undo的session kill掉,释放CPU资源,最后将数据回插到空表(数据量大的情况下需分批插入和commit,避免undo量过大导致重复这类问题),这个解决方法的局限性在于应用可否接受短暂的空表。
备注:rename正在回滚的表后,该表不会存在访问,同时后续访问该表的SQL(被替换为空表了)也不会存在效率问题,CPU资源很快能回归正常,因此问题时间段回滚速度特别慢的操作,现在也能很快完成。

常见讨论
  • 设置回滚并行度参数(fast_start_parallel_rollback),在主机资源100%的情况,无论是增加或者是减少并发回滚进程,回滚的速度都会特别缓慢(资源争用等原因),因此无法及时解决此类问题。
  • 禁用smon回滚讨论( oradebug event 10513 trace name context forever, level 2),由于问题发生在读一致性导致SQL效率低效,与smon是否回滚事务没有根本联系,因此也无法解决此类问题。
  • 增加_cleanup_rollback_entries参数值的讨论(一般增加为400-800),由于该参数需要重启数据库生效,因此也无法及时解决此类问题。
总结
  1. 一般OLTP系统,不应该存在单个session使用过高undo的情况,如果有,需要调整和优化。如果是人为执行,可能需要进行宣贯和培训;
  2. 针对这类情况的预防,可以考虑部署session  undo的使用量监控;
  3. OLAP系统,由于主要应用与分析和统计,单个session使用大量undo属于正常现象,而且由于不会有大量并发访问,因此也就不会产生上面讨论的问题
还准备总结一篇undo段损坏问题的解决,也是undo相关问题总结系列的最后一篇。





<think>好的,我现在需要回答用户关于NX次开发中“set undo mark 设置撤销标记”的问题。首先,我要确保自己对这个概念有正确的理解,然后组织一个清晰的中文解释。 首先,我应该回忆NX次开发中的撤销标记相关知识。记得在NX Open API中,Undo相关的函数用于管理撤销和重做操作,这对保持用户操作的连贯性很重要。set undo mark的作用可能是在代码中设置一个标记,以便后续的多个操作可以被撤销为一个步骤。 接下来,我需要确认具体的函数名称和用法。可能正确的函数是UF_UI_set_undo_mark,它用于在撤销列表中创建一个标记点。这样,当用户执行撤销时,从这个标记点之后的所有操作都会被撤销,直到下一个标记点。这有助于将多个相关操作分组,提升用户体验。 然后,我需要考虑使用场景。比如,当开发一个批量创建孔的功能时,每个孔的操作如果单独撤销会很麻烦。通过设置undo mark,可以将所有孔的创建合并为一个撤销步骤。这样用户只需一次撤销就能回退整个批量操作。 还要注意使用时的步骤。通常,在开始一系列操作前设置undo mark,执行完所有操作后再设置另一个标记,或者让系统自动处理。同时,要确保在适当的位置调用,避免资源泄漏或错误标记导致的问题。 可能还需要提到相关的函数,比如UF_UI_add_to_undo_list,用于将单个操作添加到撤销列表。但set undo mark的不同之处在于它管理的是操作的分组。 另外,要提醒用户注意错误处理。如果在设置标记后发生异常,可能需要清理资源,防止撤销堆栈混乱。同时,避免过多的标记影响性能,合理划分操作块。 最后,提供一个简单的代码示例会更有帮助。例如,在C#中使用Session.UndoMark.BeginMark开始一个标记,执行操作后调用EndMark。或者使用UF_UI_set_undo_mark函数,并传递合适的参数如标记名称和类型。 总结时,要强调正确使用撤销标记的重要性,既能提升用户体验,又能保证数据一致性。确保用户理解如何在实际开发中应用这一功能。</think>在NX次开发中,"设置撤销标记"是用于管理用户操作撤销/重做行为的重要机制。以下是关键知识点说明: 1. **核心功能** - 通过`UF_UI_set_undo_mark()`函数创建操作分组标记 - 将多个连续操作合并为一个撤销步骤 - 维护操作的原子性(要么全部撤销,要么全部保留) 2. **典型应用场景** ```C++ // 创建特征前设置标记 UF_UI_set_undo_mark("Create Holes", UF_UI_UNGROUPED_MARK); for(int i=0; i<10; i++){ create_hole(); // 批量创建10个孔 } UF_UI_set_undo_mark(NULL, UF_UI_END_MARK); // 结束标记 // 用户只需一次撤销即可回退全部孔创建操作 ``` 3. **参数解析** ```C++ int UF_UI_set_undo_mark( const char * undo_title, // 撤销列表中显示的操作名称 int mark_type // 标记类型: // UF_UI_BEGIN_MARK(1) 开始标记 // UF_UI_END_MARK(2) 结束标记 // UF_UI_UNGROUPED_MARK(3) 独立标记 ); ``` 4. **最佳实践建议** - **原子操作分组**:将创建复杂特征的多个步骤合并为一个逻辑操作 - **命名规范**:使用有意义的英文操作名称(如"Mirror Feature") - **错误处理**:在异常处理中调用`UF_UI_clear_undo_mark()`清除无效标记 - **内存管理**:确保BEGIN/END标记成对出现 5. **高级用法** ```C++ // 创建嵌套撤销组 UF_UI_set_undo_mark("Assembly Operation", UF_UI_BEGIN_MARK); { UF_UI_set_undo_mark("Position Component", UF_UI_BEGIN_MARK); place_component(); UF_UI_set_undo_mark(NULL, UF_UI_END_MARK); UF_UI_set_undo_mark("Add Constraints", UF_UI_BEGIN_MARK); apply_constraints(); UF_UI_set_undo_mark(NULL, UF_UI_END_MARK); } UF_UI_set_undo_mark(NULL, UF_UI_END_MARK); ``` 6. **注意事项** - 避免在循环内频繁设置标记(建议>100次操作设一个标记) - 不可跨API函数调用保留标记(每个API应独立管理) - 与`UF_UI_add_to_undo_list()`配合使用时需注意执行顺序 正确使用撤销标记可以: 1. 提升用户体验(避免零碎撤销) 2. 减少内存占用(合并操作记录) 3. 保持模型数据一致性 4. 支持复杂操作回滚 建议参考NX Open API文档中`uf_ui.h`头文件获取最新参数定义,不同NX版本可能略有差异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值