
好的,我们来详细解析一下 ORA-00080 错误。
🗄️ ORA-00080: 在指定层级等待时发生死锁
1. 官方正式说明
错误名称:ORA-00080: deadlock detected while waiting for resource at level string
官方解释:此错误表明 Oracle 数据库的死锁检测器(DEAD)在分布式事务或并行服务器(Oracle RAC)环境中检测到了一个死锁。与常见的 ORA-00060 死锁不同,ORA-00080 特别指出了死锁发生在某个特定的“层级”(Level),这个层级通常与系统资源(如缓冲区缓存、数据块等)的访问优先级或锁定顺序相关。
错误信息结构:
ORA-00080: deadlock detected while waiting for resource at level %s
%s是一个变量,会被一个数字替换,例如4。这个数字代表了发生死锁的资源层级(Level)。不同的层级代表不同类型的系统资源或锁。
2. 错误原因与原理
-
根本原因:与所有死锁一样,其根本原因是多个会话(或进程)之间形成了循环等待资源的关系。会话A持有资源X并等待资源Y,而会话B持有资源Y并等待资源X。在Oracle RAC(实时应用集群)环境中,这种争用可能发生在不同实例之间,涉及全局缓存(Global Cache)和全局队列服务(GES/Global Enqueue Service)的锁。
-
层级(Level)的含义:Oracle 内部使用一个复杂的锁机制来管理对共享资源的访问。为了高效地检测和处理死锁,这些资源被分配了不同的“层级”或优先级。层级决定了锁的获取顺序,以避免死锁。系统规定,会话在请求更高层级的锁之前,必须先获取所需的所有较低层级的锁。如果违反了这种严格的层级锁定顺序,就可能引发死锁,并被ORA-00080错误捕获。
-
与ORA-00060的区别:ORA-00060 通常报告的是应用级别的死锁(例如,两个事务互相锁定了对方需要的表行)。而 ORA-00080 更多涉及的是 Oracle内核层面的、更深层次的资源死锁,通常与内存结构、数据块访问、RAC实例间的通信有关,对DBA和开发者来说更底层、更复杂。
3. 常见场景
- Oracle RAC环境:这是ORA-00080最常发生的环境。多个实例同时访问共享磁盘上的相同数据块,在高并发写入场景下,极易在不同实例的进程之间发生全局缓存锁等待循环。
- Bug或内部错误:某些Oracle版本的内部缺陷可能会导致即使在看似合理的操作下,也错误地触发了层级死锁检测。
- 非RAC环境下的罕见情况:在单实例数据库中,如果遇到非常底层的资源争用(如某些特定的后台进程冲突),也可能触发此错误,但这相对少见。
4. 相关联的其他ORA错误
- ORA-00060: 标准的应用层死锁错误。这是最常见的死锁错误。
- ORA-00448: 后台进程正常终止。有时后台进程(如LMSn)因死锁或其他问题失败会抛出此错误。
- ORA-29740: 全局队列服务进程(LMSn)出现致命错误。这在RAC死锁中经常伴随出现。
- ORA-600/ORA-7445: 内部错误。某些底层bug导致的死锁可能最终表现为这些内部错误。
5. 定位原因与分析过程
- 检查警报日志(Alert Log):这是第一步也是最重要的一步。Oracle在检测到死锁时,会在警报日志中生成一个详细的跟踪文件(trace file),其中包含死锁图(Deadlock Graph)。
- 分析跟踪文件:找到警报日志中提到的跟踪文件(通常位于
diag/rdbms/<db_name>/<instance_name>/trace目录下)。使用文本编辑器打开它。在这个文件中,你需要寻找:- 死锁图:它会以图形化的文本方式展示哪些会话、哪些进程、在等待哪些资源,并清晰地指出了循环等待的路径。
- 涉及会话的SQL语句:文件会记录导致死锁的SQL语句的SQL_ID,甚至完整的SQL文本。
- 资源信息:会显示发生死锁的具体资源(如数据块地址、表名等)。
- 查询数据字典:结合跟踪文件中的信息,可以进一步查询相关会话和SQL的历史信息。
-- 根据SQL_ID查找SQL文本 SELECT SQL_TEXT FROM V$SQL WHERE SQL_ID = '&sql_id_from_trace'; -- 查看近期会话活动(需要Diagnostics Pack许可) SELECT * FROM DBA_HIST_ACTIVE_SESS_HISTORY WHERE SAMPLE_ID = &sample_id_from_trace;
6. 解决方案与预防措施
即时解决
- 与ORA-00060一样,Oracle已经自动选择了一个“牺牲品”会话,并将其事务回滚。应用程序收到此错误后,应该捕获异常并重试被回滚的事务。
- 通常不需要立即手动干预,因为死锁已被数据库自动解决。
根本性解决与预防
- 应用层优化:
- 提交频繁:确保事务尽可能短小,操作完成后立即提交。
- 访问顺序:如果可能,让所有程序以相同的顺序访问多个表或数据块。
- 数据库层优化(尤其在RAC中):
- 分区(Partitioning):使用分区表将数据分散到不同的物理段中,可以减少多个实例对同一数据块的争用(减少"热点块")。
- 序列缓存(Sequence Cache):为应用程序使用的序列(Sequence)设置较大的
CACHE大小(如CACHE 1000),以避免序列号生成成为RAC中的全局争用点。 - 反向键索引(Reverse Key Index):对于高度递增的索引列(如使用序列填充的主键),使用反向键索引可以将插入分散到索引的不同块中,避免索引叶块的争用。
- 检查并应用补丁:由于ORA-00080很多时候与内部Bug相关,查询Oracle官方支持网站(My Oracle Support),根据您的版本和跟踪文件中的内部信息(如错误参数),查找是否有相关的已知Bug和补丁程序。
- 调整初始化参数:在Oracle RAC中,某些参数可能会影响全局缓存性能,但调整这些参数需要非常谨慎,最好在Oracle支持人员的指导下进行。例如:
_gc_policy_time: 影响缓存融合策略。_gc_affinity_time: 影响主节点亲和力。_gc_defer_time: 影响全局缓存延迟处理。
7. 通俗易懂的讲解
可以把数据库想象成一个大型共享仓库(RAC就是多个仓库房间共享一个库存)。
- 数据块:仓库里的一个个货箱。
- 会话:一个个仓库管理员,负责搬货和记录。
- 锁:管理员在货箱上贴的便签,写上“我正在清点”(共享锁)或“我正在搬走”(排他锁)。
ORA-00080死锁就像是这样一个场景:
- 管理员小王(实例1的进程)在A区拿住了货箱123的“正在搬走”便签(层级4的锁),然后他走去B区,想给货箱456也贴上“正在搬走”的便签。
- 与此同时,管理员小张(实例2的进程)在B区拿住了货箱456的“正在搬走”便签(同样是层级4的锁),然后他走去A区,想给货箱123也贴上“正在搬走”的便签。
- 结果,小王在B区等着小张放开456号箱,小张在A区等着小王放开123号箱。两个人互相瞪眼,谁都干不了活,工作流程完全卡死了。
这就是一个死锁(Deadlock)。
“在指定层级等待” 的意思是,仓库规定,贴“水果箱”的便签(假设是层级3)必须在贴“电器箱”的便签(层级4)之前。但如果两个管理员都违反了这个规定,先抢着贴了高层级的电器箱便签,然后才去争抢对方的水果箱便签,系统就会检测到这种违反规则造成的死锁,并报告 ORA-00080。
数据库怎么办? 仓库总监(Oracle死锁检测器)会立刻过来,随机选择一个人(比如小王),对他说:“你(的事务)放手,从头再来一遍!” 然后小王手上的便签被撕掉,他搬的货箱放回原处,他收到一个ORA-00080错误报告。这样,小张就可以顺利工作了。小王抱怨一句,然后只好重新开始他的搬货流程(应用程序重试事务)。
如何避免?
- 让大家约定好,都按固定的区域顺序干活(统一访问顺序)。
- 加快干活速度,干完一个区域赶紧把便签撕掉(频繁提交)。
- 把热门货品(热点数据)分散到不同的货架上(分区)。
- 有时候是仓库本身的设计图(Oracle软件版本)有毛病,需要找设计师(Oracle支持)打补丁。
希望这个解释能帮助您更好地理解 ORA-00080 错误。
欢迎关注我的公众号《IT小Chen》

被折叠的 条评论
为什么被折叠?



