怎么快速查MSSQL数据库里锁表情况,防止卡死和堵塞问题
- 问答
- 2026-01-21 19:43:10
- 4
要快速查看MSSQL数据库里的锁表情况,防止因为锁的问题导致数据库卡死或操作堵塞,可以按照以下几个步骤和方法来进行,这些方法主要参考了微软官方文档中关于动态管理视图(DMV)和活动监视器的描述,以及数据库管理员社区的常见实践经验。
最直接快速的方法是使用SQL Server Management Studio(SSMS)这个管理工具自带的图形化界面功能,打开SSMS,连接到你的数据库服务器,然后右键点击服务器名称,选择“活动监视器”,在活动监视器打开后,找到“进程”这个页面,你可以看到一个列表,列出了当前所有正在数据库上执行的操作(也就是进程),你需要重点关注以下几列信息:“会话ID”、“用户”、“状态”、“阻塞者”、“头阻塞程序”和“命令”,如果某个操作被卡住了,很可能是它被另一个操作锁住了资源,这时候,你就在“阻塞者”这一列找数字,如果某个会话ID的“阻塞者”列是空的,说明它没有阻塞别人;如果这里有一个数字,比如是“55”,那就说明这个会话(比如ID是73)被会话ID为55的操作给阻塞了,更厉害的是“头阻塞程序”,如果一个会话的“头阻塞程序”列有值,比如是“55”,而“阻塞者”也是“55”,这说明55这个会话是导致一系列阻塞的罪魁祸首,也就是阻塞链的源头,找到这个源头ID后,你可以右键点击它,选择“终止进程”,强行把这个卡住别人的操作停掉,这样被阻塞的操作就能继续进行了,这是一种非常直观的应急处理方法。
图形化界面有时候可能因为服务器负载高而本身响应慢,或者你需要更详细的信息来分析根本原因,这时候,直接运行一些SQL查询语句会更有效、更强大,这些查询主要利用的是SQL Server内部的一些“动态管理视图”,这些视图就像一个个小窗口,可以让你实时看到数据库内部的运行状态。

第一个常用的查询是查看当前正在发生的阻塞情况,你可以运行类似下面的语句:
SELECT
t.blocking_session_id AS '正在阻塞别人的会话ID',
s.blocking_session_id AS '被谁阻塞的会话ID',
s.session_id AS '会话ID',
s.login_name AS '登录用户',
s.host_name AS '主机名',
t.wait_type AS '等待类型',
t.wait_resource AS '等待的资源',
s.program_name AS '程序名',
t.text AS '执行的SQL语句'
FROM sys.dm_exec_connections AS c
INNER JOIN sys.dm_exec_sessions AS s ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) AS t
WHERE s.session_id IN (SELECT blocking_session_id FROM sys.dm_os_waiting_tasks WHERE blocking_session_id IS NOT NULL)
OR s.session_id IN (SELECT session_id FROM sys.dm_os_waiting_tasks WHERE blocking_session_id IS NOT NULL)
这个查询看起来复杂,但它的核心目的是找出谁阻塞了谁,以及这些会话正在执行什么SQL命令,结果中的“正在阻塞别人的会话ID”就是问题源头。“等待类型”很重要,如果看到“LCK_M_X”(排他锁等待)或“LCK_M_S”(共享锁等待)之类的,就明确是锁的问题。“执行的SQL语句”能让你知道是哪个操作惹的祸,可能是你写的某个UPDATE语句没提交事务。

第二个查询是更全面地查看当前数据库的所有锁,可以运行:
SELECT
dm_tran_locks.request_session_id AS '会话ID',
DB_NAME(dm_tran_locks.resource_database_id) AS '数据库名',
CASE dm_tran_locks.resource_type
WHEN 'OBJECT' THEN OBJECT_NAME(dm_tran_locks.resource_associated_entity_id)
WHEN 'PAGE' THEN '(页)'
WHEN 'KEY' THEN '(键)'
ELSE '(其他)'
END AS '锁定的对象',
dm_tran_locks.resource_type AS '资源类型',
dm_tran_locks.request_mode AS '锁模式',
dm_tran_locks.request_status AS '请求状态'
FROM sys.dm_tran_locks
WHERE dm_tran_locks.resource_database_id = DB_ID('你的数据库名') -- 替换成你的数据库名
这个查询能列出当前数据库里所有的锁,你需要关注“锁定的对象”是哪张表(OBJECT),“锁模式”是什么(比如X代表排他锁,力度大,容易阻塞别人;S代表共享锁,力度小),“请求状态”是“GRANT”(已获得)还是“WAIT”(正在等待),如果一张表上有大量的“WAIT”状态的X锁,那它很可能就是瓶颈所在。
知道了怎么查,更重要的是怎么预防和从根源上解决,避免频繁出现锁表卡死,预防措施比事后排查更重要,第一,事务要尽可能的短小精悍,一个事务里不要包含太多操作,特别是不要在事务里进行人工交互(比如在代码里开始一个事务,然后等待用户点击确认按钮再提交),这是导致长时间锁定的最常见原因,做完操作后立刻提交或回滚事务,第二,检查你的SQL语句是否写得合理,UPDATE语句的WHERE条件是否没有用到索引,导致数据库不得不锁住整张表(表锁)来查找要更新的行,而不是只锁住相关的几行(行锁),这种全表扫描是性能杀手,通过查看执行计划,确保你的查询使用了正确的索引,第三,考虑使用乐观并发控制或读取快照隔离级别,在SQL Server中,可以设置数据库选项READ_COMMITTED_SNAPSHOT为ON,这样在默认的读已提交隔离级别下,读操作不会阻塞写操作,写操作也不会阻塞读操作,它能很大程度上缓解阻塞问题,因为读者不会申请共享锁,也就不会和写着排他锁冲突,这需要额外的空间来存储版本,并且对tempdb数据库有一定压力,需要评估硬件资源,第四,在业务低峰期执行那些需要长时间运行、会影响大量数据的维护操作(比如大批量数据更新、重建索引等),尽量减少对正常业务的影响。
快速排查锁表问题,先用SSMS的活动监视器定位阻塞源头并紧急处理(终止进程),然后用DMV查询深入分析阻塞链和锁的详细信息,长远来看,通过优化事务设计、改进SQL语句和索引、合理使用数据库隔离级别等手段,可以从根本上减少锁冲突的发生,保持数据库的流畅运行,这些方法结合了微软官方技术文档(如sys.dm_tran_locks, sys.dm_os_waiting_tasks等DMV的说明)和实际运维中的有效经验。
本文由颜泰平于2026-01-21发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/84155.html