语句突然不动,CPU 也不高,先看是不是被别的会话堵住了。堵住别人的那个会话叫 blocker,被堵住的是 waiter。要结束的是最上面那个 blocker,而不是每一个正在等待的会话。CPU 已经打满时,先看 正在跑的语句,这篇只处理阻塞。
在要查的实例上执行。blocking_session_id 不是 0,表示这一行正在等另一个会话。
1 | SELECT |
wait_type 常见是 LCK_M_S、LCK_M_X 这类锁等待。wait_time 单位是毫秒。running_statement 是当前这条语句,不是整个批处理。
最上面的 blocker 往往没有出现在 sys.dm_exec_requests 里,因为它已经不在跑请求,只是还拿着锁。用会话号去会话视图看是谁:
1 | SELECT |
open_transaction_count 大于 0,说明事务还没提交或回滚。再看它最后执行的语句:
1 | DBCC INPUTBUFFER(54); |
应用连接池里,program_name 经常是同一串,要靠 host_name 和 last_request_start_time 对到那一次操作。
确认这是堵住别人的会话、并且事务可以放弃之后,才结束它:
1 | KILL 54; |
KILL 会回滚这个会话未提交的事务。事务很大时,回滚期间锁还在,等待不会马上消失。不要对一串 waiter 逐个 KILL。waiter 的 blocking_session_id 指向谁,就先处理谁;那个人如果也被别人堵住,继续往上找,直到 blocking_session_id 为 0 或者这个会话已经不在 dm_exec_requests 里。