如果语句处于活动状态,且在vtrxwaitc查询中有返回记录,说明语句有等待发生,然后通过WAIT_FOR_ID字段到vsessions中定位到所等待的会话信息,一般来说,都是因为某些会话或者客户端忘记进行提交或者回滚操作,后续就一直空闲了,导致其他的事务由于跟该事务存在一些事务上的依赖关系发生等待,针对这种情况,我们需要在确认安全的情况针对这个阻塞源头会话进行操作,关闭客户端 /CLOSE 会话/发送提交或者回滚命令等。
另外一种等待不会通过 VTRXWAIT 查询得到结果,比如某些表发生 DDL 操作过程中,其他的会话尝试对该表进行查询,由于字典对象发生变化,所以发生字典对象的等待,这种阻塞可以通过查询 SELECT * FROM vlock WHERE blocked = 1 来进行确认,查询结果中可以对相关锁对象的持有事务来查询 V$SESSIONS,来确认阻塞来源。
一般情况下这种 DDL 导致的等待会有一个显示的等待时间,由 dm.ini 参数 DDL_WAIT_TIME 来进行控制,默认是 10,也就是说如果等待 10 秒钟后,阻塞源头的 DDL 还没有执行完释放资源,会抛出锁超时错误。
还有一些其他情况造成的等待:
(1)查询中由于存在临时表 /SORT/HASH JOIN/HAGR 等操作导致使用的临时表空间,INI 参数又限制了 TEMP 表空间大小,在临时表空间没有被其他会话使用完并释放时发生等待。
(2)主备、读写分离等环境运行过程中,由于备机自身或者配置相关的原因(备机 IO 出现异常、主备网络异常、数据延迟达到配置的主备最大延迟)等,导致主机上运行一些需要刷 REDO 日志的语句发生等待,这种等待需要备机上的这些现象缓解之后才会解开。
(3)大表发生 DELETE 量数据、TRUNCATE 后,对该表的查询或者 DML 操作缓慢,这个时由于大批量删除数据之后,由于这些数据都只是被标记删除,在一定事件后会由回收站进行统一的清理操作,清理过程中需要对数据页进行修改,而涉及的数据页又非常多,所以导致执行速度缓慢。
(4)数据库自身 BUG 导致的死锁,正常情况下,如果存在某些事务互相等待的情况,数据库会主动抛出死锁报错,但是如果时数据库内部自身 BUG,导致自身的一些临界区资源出现死锁,是不能自动处理的,一般我们最后考虑这种情况。