说到Oracle Data Guard的Switchover流程,主库上那些未提交的长事务往往是最棘手的障碍。当你执行alter database commit to switchover时,要么直接卡住不动,要么弹出ORA-16139: media recovery required或SWITCHOVER_STATUS = SESSIONS ACTIVE的报错。不把这些“顽固事务”提前清理干净,切换根本无法顺利进行。

锁定罪魁祸首:确认主库是否存在未提交的长事务
仅依靠v$transaction中的start_time字段判断并不充分,你还需结合会话的活跃状态以及锁的持有情况综合评估。
- 执行以下SQL语句,找出运行超过10分钟且状态为
ACTIVE的会话:SELECT s.sid, s.serial#, s.username, s.status, t.start_time, t.used_ublk FROM v$session s, v$transaction t WHERE s.taddr = t.addr ORDER BY t.start_time; - 随后将该结果关联到
v$locked_object视图。如果该会话正持有行锁或DML锁(lock_type = 'TX'),基本可以确定就是这个未提交的事务在阻塞切换。 - 这里有一个易忽略的细节:
v$transaction中的start_time记录的是事务启动时刻,而非SQL实际执行的时间。部分应用在开启事务后长时间处于空闲状态,例如等待前端上传数据,这类情况也容易被误判为“长事务”。因此,仅凭数据无法下定论,还需人工核实业务逻辑。
Switchover前的“清场”行动:两类事务,两种应对策略
主库上的未提交事务实际上可分为两类。一类是“真正长事务”,例如批量导入中途意外中断;另一类是“伪长事务”,比如连接池中那些空闲但事务未关闭的会话。处理方式截然不同。
- 对于已确认业务可中断的“真正长事务”,直接使用
alter system kill session 'sid,serial#' immediate;强制终止,Oracle会自动回滚其变更(前提是UNDO空间充足)。 - 对于“伪长事务”,常见于Java应用未调用
connection.commit()或rollback()。此时的首要任务是联系开发人员,确认能否主动提交或回滚。若无法及时联系,再考虑kill session——否则应用层可能触发一轮重试风暴,反而更麻烦。 - 需要反复强调:千万不要在主库上执行
send extract, forcetrans或skiptrans这类命令,那是GoldenGate的操作,与DG切换完全无关。
验证阶段卡住了?别慌,逐层排查
执行alter database switchover to physical standby verify;后,如果返回ORA-16139错误,表明MRP进程尚未收完主库发送的最后一批Redo,或者主库仍有未刷盘的Redo缓存。
- 首先检查主库的
v$archive_dest_status视图,确认dest_id=2对应的status是否为VALID,且error字段为空。 - 在主库上手动触发日志切换是个有效方法:执行
ALTER SYSTEM ARCHIVE LOG CURRENT;重复两到三次,确保所有Redo均已传输到备库。 - 随后在备库上进行比较:
SELECT MAX(sequence#) FROM v$archived_log WHERE applied='YES';与SELECT MAX(sequence#) FROM v$log_history;,两者的差值应≤1。若差距较大,说明MRP尚未追平,此时绝不能强行切换。
最后补充一个最容易被忽略的关键点:DG切换本质上并非纯粹的数据库操作,它依赖于主库发出的End of Redo标记。这个标记只有在主库所有当前事务均完成提交或回滚后才会生成。只要存在一个未决事务,该标记就无法发出——因此,切勿试图跳过事务排查直接硬切,那无异于给自己埋雷。
