SQL如何手动释放死锁_KILL命令与事务进程终止

1次阅读

要查出正在阻塞别人的事务 ID,需查询 sys.dm_exec_requests 中 blocking_session_id≠0 的会话;若 blocking_session_id= 0 但 wait_type 为 LCK_M_* 且状态为 suspended,则可能处于死锁链中。

SQL 如何手动释放死锁_KILL 命令与事务进程终止

怎么查出正在阻塞别人的事务 ID

死锁发生后,SQL Server 不会自动告诉你哪个会话在“卡着”别人,得自己挖。核心是查 sys.dm_exec_requestssys.dm_exec_sessions,重点关注 blocking_session_id 不为 0 的行。

实操建议:

  • 运行 SELECT session_id, blocking_session_id, status, command, wait_type, last_wait_type FROM sys.dm_exec_requests WHERE blocking_session_id 0,快速定位“真凶”会话
  • 如果 blocking_session_id = 0 但状态是 suspendedwait_typeLCK_M_*,说明它自己也在等锁,可能是死锁链一环
  • 别只看 sp_who2 —— 它不显示阻塞层级关系,容易漏掉嵌套阻塞
  • 注意 session_id 是正整数,而系统会话(如 session_id)不能 KILL,强行执行会报错 <code>Msg 6105, Level 14, State 1

KILL 命令到底该杀谁:不是死锁报告里的 SPID,而是阻塞源头

SQL Server 的死锁图(deadlock graph)里会列出两个 victim 和 owner,但 KILL 的目标不是图里标红的那个“victim”,而是那个长期持有锁、没提交 / 回滚、还在阻塞别人的会话。

实操建议:

  • 先用上一步查到的 blocking_session_id 去关联 sys.dm_exec_sessions,确认该会话的 login_namehost_nameprogram_name,避免误杀运维或监控连接
  • KILL 后事务会自动回滚,但回滚时间取决于已执行的修改量——大事务可能卡住几分钟,期间仍占用资源,status 显示为 rollback
  • 不要对 session_id = 1(system process)或任何 session_id 执行 <code>KILL,会直接报错 Cannot use KILL to kill your own process 或权限拒绝

为什么 KILL 了还继续阻塞:事务没真正结束的三个信号

KILL 发出去不代表锁立刻释放。常见现象是查 sys.dm_exec_requests 还能看到该 session_idstatusrollback,或者干脆查不到但它锁还挂着——这说明事务回滚没完成,或锁被延迟释放。

实操建议:

  • 检查 sys.dm_tran_locks:如果 request_session_id 还存在,且 resource_typeOBJECTPAGE,说明回滚中锁未清
  • 观察 sys.dm_exec_sessions 中对应会话的 is_user_process 是否为 0 —— 如果是,说明已被标记终止但内核线程还没退出
  • 别急着再 KILL 一次,重复执行同个 session_id 会报 Msg 6107, Level 14, State 1: The specified session ID does not exist,因为命令已入队,只是没执行完
  • 极端情况下(如回滚卡死),可能需要重启 SQL Server 实例,但这属于兜底操作,不是常规手段

如何防止下次又手动 KILL:从应用层堵住根源

手动 KILL 是救火,不是方案。90% 的可复现死锁,根子在应用代码没控制好事务边界和访问顺序。

实操建议:

  • 所有显式事务必须有超时设置:.NET 用 TransactionOptions.Timeout,Java 用 @Transactional(timeout = ……),避免无限期等待
  • 统一 DML 操作顺序:比如固定先更新 Orders 再更新 OrderItems,避免 A 进程按 AB 顺序、B 进程按 BA 顺序加锁
  • 避免在事务里做 HTTP 调用、文件读写、长时间计算 —— 这些会让事务 hold 锁时间不可控
  • SET LOCK_TIMEOUT 5000 加到连接字符串或会话开头,让语句等锁超过 5 秒就直接报错,而不是变成阻塞源

死锁本身不可怕,可怕的是把它当成偶发故障忽略。真正难处理的,是那种每小时出现一次、每次锁住 3–4 个关键表、但日志里只留下一行 Deadlock encountered …… Deadlock victim 的场景——这时候光靠 KILL 解不了,得翻应用日志比对事务入口点。

text=ZqhQzanResources