
让我为你详细解析 Oracle 数据库中的 ORA-00031 错误。我会先提供官方正式说明,再用通俗易懂的方式讲解,最后给出诊断方法和解决方案。
📋 官方正式说明
错误代码: ORA-00031
错误信息: session marked for kill
中文翻译: 标记要终止的会话
官方解释(根据Oracle文档):
ORA-00031 错误表示在
ALTER SYSTEM KILL SESSION命令中指定的会话无法被立即终止(通常是因为该会话正在回滚事务或阻塞在一个网络操作上),但它已被标记为终止状态。这意味着 Oracle 会在此会话当前不可中断的操作完成后,尽快将其终止。无需其他操作来终止此会话,但对此会话再次执行ALTER SYSTEM KILL SESSION命令可能会使其更快被终止。
🧐 通俗易懂的语言讲解
一句话解释: 你让数据库“开除”一个正在干活的“员工”(会话),但这个员工手头有件急事必须干完(比如正在回复一个重要的请求或者正在撤销刚才的操作),数据库管理员对他说:“你干完手头这事就马上走人”,并且给他打了个“标记”。你等不及又催了一次,系统就回复你:“已经标记了,催也没用,得等他忙完”。
举个例子:
想象一个会话正在执行一个更新百万条数据的大事务,但没提交。
- DBA 发现它有问题,执行了
ALTER SYSTEM KILL SESSION '123, 4567'。 - 数据库收到指令,但发现这个会话正在“回滚”(撤销)之前的所有修改(这是一个无法瞬间中断的原子操作)。
- 数据库于是将会话状态设置为
KILLED,并告诉DBA:ORA-00031,意思是“已标记,完事就踢它”。 - 此时,这个会话会继续完成它的回滚操作,在此期间它可能仍然占用着某些资源(如锁)。一旦回滚完成,后台进程 PMON 就会彻底清理它。
🔍 原因与原理
- 根本原因:Oracle 的会话终止是异步的。
KILL SESSION命令并非立即“杀死”服务器进程,而是向后台进程 PMON (Process Monitor) 发出一个请求,由其负责清理工作。 - 数据库原理:
- 当会话被标记为终止时,PMON 会等待该会话完成其当前的不可中断操作(Uninterruptible Operation),例如:
- 事务回滚 (Rollback):确保数据一致性和完整性,这是最重要的原因。
- 网络操作等待:会话正在等待网络数据包。
- 长时运行查询:正在从磁盘读取大量数据。
- 在此期间,会话在
V$SESSION视图中的STATUS会变为KILLED。 - 一旦不可中断的操作完成,PMON 会立即介入,释放该会话持有的所有锁(Locks)和闩锁(Latches),回滚未提交的事务,并释放其占用的内存资源(如 PGA 和 UGA)。
- 当会话被标记为终止时,PMON 会等待该会话完成其当前的不可中断操作(Uninterruptible Operation),例如:
- 为何资源不立即释放?这是 Oracle 的一种保护机制,旨在防止强行终止正在进行关键操作(如大规模数据回滚)的会话导致数据库处于不一致的状态。
⚠️ 常见发生场景
- 终止长事务会话:尝试终止一个正在执行大规模
INSERT、UPDATE、DELETE且未提交的会话。 - 处理锁冲突:为了解决锁表(例如,一个会话持有锁而不提交,阻塞了其他会话)而终止阻塞者时。
- 中断长时间运行的操作:终止正在执行复杂查询或数据导出的会话。
- 应用程序异常后:应用程序发生故障(如崩溃)后,残留的会话可能处于某种中间状态,导致终止缓慢。
- DDL 语句等待:会话可能在等待某个资源以执行 DDL 语句,此时终止它也会触发此错误。
🔗 相关联的其他 ORA 错误
- ORA-00028: your session has been killed:这是被终止的会话(“受害者”)下一次尝试操作时收到的错误。它成功接收到终止信号。ORA-00031 是“杀手”收到的警告,ORA-00028 是“受害者”收到的死亡通知。
- ORA-00030: User session ID does not exist:尝试操作一个不存在的会话 ID,可能发生在会话已被完全清理之后。
- ORA-04021: timeout occurred while waiting to lock object:在等待锁定对象时发生超时,可能与另一个即将被终止但尚未释放锁的会话有关。
📊 诊断与定位方法
当遇到 ORA-00031 错误或怀疑会话无法被彻底终止时,可以遵循以下流程进行诊断和排查:
flowchart TD
A[遭遇 ORA-00031 或会话长时间无响应] --> B[查询被锁对象与会话信息]
B --> C[尝试用ALTER SYSTEM KILL SESSION终止会话]
C --> D{是否报错ORA-00031<br>或会话状态仍为KILLED?}
D -- 否 --> E[问题解决]
D -- 是 --> F[查询会话对应的操作系统SPID]
F --> G[在操作系统级别杀死进程<br>(Linux: kill -9 / Windows: orakill)]
G --> H[确认资源是否释放]
H --> I[问题解决]
以下是流程中关键步骤需要用到的 SQL 语句:
-
查询被锁对象和对应会话信息
SELECT /*+ rule */ l.session_id sid, s.serial#, l.locked_mode, l.oracle_username, s.osuser, s.machine, s.program, o.object_name, s.logon_time FROM v$locked_object l, v$session s, dba_objects o WHERE l.session_id = s.sid AND l.object_id = o.object_id ORDER BY sid, s.serial#; -
查询状态为
KILLED的会话SELECT s.sid, s.serial#, s.status, p.spid, s.osuser, s.program FROM v$session s, v$process p WHERE s.paddr = p.addr AND s.status = 'KILLED'; -- 重点查看状态为KILLED的会话 -
根据 SID 查找操作系统进程 ID (SPID)
SELECT s.sid, s.serial#, s.status, p.spid, p.pid, s.osuser, s.program FROM v$session s, v$process p WHERE s.paddr = p.addr AND s.sid = &target_sid; -- 替换为具体的SID
🛠️ 解决方案
方案一:等待 PMON 自动清理(轻度场景)
- 操作:如果会话正在回滚一个大型事务,有时最明智的选择是等待 PMON 完成清理工作。强行中断可能导致更严重的问题。
- 如何监控:你可以通过查询
V$SESSION观察STATUS是否为KILLED,或使用V$TRANSACTION视图查看回滚进度。
方案二:在操作系统级别终止进程(强烈推荐,彻底有效)
当你无法忍受等待,或者会话僵死(KILLED 状态一直不消失)时,这是最有效的方法。
-
Linux/Unix 系统:
- 使用上一步查询到的
SPID(例如12345)。 - 在数据库服务器上,以 oracle 用户或 root 用户执行:
kill -9 12345
- 使用上一步查询到的
-
Windows 系统:
- 使用上一步查询到的
SPID(例如12345)。 - 打开命令提示符,使用
orakill命令(Oracle 自带):orakill <ORACLE_SID> 12345<ORACLE_SID>:你的数据库实例名(可通过SELECT name FROM v$database;查询)。
- 使用上一步查询到的
⚠️ 注意:
- 操作前务必再次确认
SPID,杀错系统进程可能导致数据库实例崩溃。 kill -9和orakill是强制手段,会立即终止进程,可能导致正在进行的事务无法回滚,因此应作为最后的手段。
方案三:重启数据库实例(最终手段)
- 操作:如果存在大量无法终止的会话,或者操作系统级终止后数据库出现不稳定状况,可以考虑重启实例。
- 警告:这是破坏性最大的方案,会影响所有用户。务必在业务低峰期进行,并做好备份和沟通。
SHUTDOWN IMMEDIATE; -- 尝试正常关闭 STARTUP; -- 如果正常关闭失败,可能需要使用 SHUTDOWN ABORT
💡 核心解决方案总结
| 方案 | 适用场景 | 优点 | 缺点 | 操作级别 |
|---|---|---|---|---|
| 等待PMON清理 | 会话正在正常回滚 | 安全,数据一致 | 可能需要长时间等待 | 数据库内部 |
| 操作系统级终止 | 会话僵死或急需释放资源 | 快速,有效 | 有一定风险,可能影响稳定性 | 操作系统 |
| 重启数据库实例 | 大规模问题或数据库僵死 | 彻底解决 | 影响所有用户,破坏性大 | 数据库实例 |
希望以上详细的解释和解决方案能帮助你彻底理解并解决 ORA-00031 错误。记住,操作系统级的 kill 命令虽然强大,但需谨慎使用。
欢迎关注我的公众号《IT小Chen》
1206

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



