在SQL Server查询中找出已获取的锁定?

8

我有一个来自我的应用程序的SQL语句。我想知道这个语句获得了哪些锁定;如何在SQL服务器中实现? 这个语句已经涉及到死锁,我正在尝试分析;我无法重现死锁。 我正在运行MS SQL Server 2005。

6个回答

7

您可以在事务中运行该语句,但不提交该事务。由于锁将保持到事务提交,因此这给您检查锁的时间。(默认情况下,不是无限期,而是5分钟。)

例如:

BEGIN TRANSACTION
select * from table

然后打开管理工具并检查锁定情况。它们在“管理” -> “活动监视器” -> “按对象锁定”或“按进程锁定”中。完成后,请运行:

COMMIT TRANSACTION

释放锁定。

1
好主意!开始事务,但不要提交以获取给定查询的锁定详细信息。如果没有管理工具,则简单的 `SELECT * FROM sys.dm_tran_locks' 也可以帮助查看有关已获取锁定的详细信息。 - sapan

3
我建议您首先打开死锁检测跟踪标志,而不是无限运行分析器跟踪。
这样,事件详情将被记录到SQL Server错误日志中。
请查看以下Books Online参考以了解各种跟踪标志的详细信息。您需要使用1204和/或1222。
请务必启用具有服务器范围而不仅仅是当前会话的跟踪标志。例如使用: http://msdn.microsoft.com/en-us/library/ms188396(SQL.90).aspx
DBCC TRACEON(1222,-1)

有趣的是,我如何在查询分析器中设置标志呢? 这里是否涉及任何额外开销? - Tomas
我运行了"DBCC TRACEON(1222,-1)"和"DBCC TRACEON(1204 ,-1)",并启动了死锁图跟踪(在SQL Server 2005上)。当我强制发生死锁时,跟踪捕获了它。然而,在SQL Server错误日志中没有死锁的记录。我正在SQL Server Management Studio中查看"SQL Server Agent"+"Error Logs"+"Current -"+右键单击+"View Agent Log",我可能做错了什么? - KM.
你正在查看错误的日志,那些是代理日志。请前往“管理”>“SQL Server 日志”。 - Sam
@Tomas:正如Sam所提到的,您需要查看SQL Server日志,而不是SQL Server代理日志。 - John Sansom
@Sam,谢谢,我现在找到了。信息看起来包含大致相同的内容(日志与跟踪XML文件),但XML文件更容易查看。 - KM.

3

这里有一个查询,可以显示所有活动锁定、谁拥有它们以及它们所在的对象。我很久以前从Technet文章中找到了它。它适用于SQL 2000和2005(对于2005,请将sysobjects更改为sys.objects)。如果您想将其限制为仅针对此数据库和独占锁,请取消WHERE子句的注释。

select 'Locks' as Locks,
    spid, nt_username, name, hostname, loginame, waittime, open_tran,
    convert(varchar ,getdate() - last_batch, 114) as TimeSinceLastCommand,
    case req_mode
    when  0 then 'Not granted'
    when  1 then 'Schema stability'
    when  2 then 'Schema modification'
    when  3 then 'Intent shared'
    when  4 then 'Shared intent update'
    when  5 then 'Intent shared shared'
    when  6 then 'Intent exclusive'
    when  7 then 'Shared Intent Exclusive'
    when  8 then 'Shared'
    when  9 then 'Update'
    when 10 then 'Intent insert NULL'
    when 11 then 'Intent shared exclusive'
    when 12 then 'Intent update'
    when 13 then 'Intent shared-update'
    when 14 then 'Exclusive'
    when 15 then 'Bulk operation'
    else str(req_mode) end as LockMode
from master..syslockinfo
    left join sysobjects so on so.id = rsc_objid
    left join master..sysprocesses sp on sp.spid = req_spid
--where rsc_dbid = (select db_id()) and ltrim(req_mode) in (6,7,11,14) 

小注释:对于SQL 2012,数字有些不同:http://technet.microsoft.com/zh-cn/library/ms189497.aspx - n0rd

2
在分析器中运行跟踪(选择空白模板),选择死锁图事件,并在出现的新选项卡(事件提取设置)上保存每个事件(勾选单独保存死锁XML事件),保存到各自的文件中。在XML查看器中打开此文件,就可以很容易地了解发生了什么。每个进程都包含有一堆过程调用等信息,所有锁定也都在其中。
让此跟踪一直运行,直到死锁再次发生,只有在死锁发生时才会记录信息,因此开销不大。如果它再也没有发生,那么问题已经解决,否则你已经捕获了所有信息。

但是要做到这一点,我必须在运行跟踪时重新创建场景吗?我无法复制该场景。 - Tomas
运行该跟踪的开销是多少? - Tomas
跟踪的开销可能非常大,如果您选择了大量事件(有些事件每次执行过程中的每个语句都会触发,另一些则在每次完成时触发等),那么您可以在短时间内收集到大量数据。如果您只选择死锁图事件,则只会在死锁发生后获取数据,希望这在您的系统上很少发生。 - KM.
1
我们在一个使用频繁的生产系统上运行了带有死锁过滤器的性能分析器。这似乎并没有影响性能。 - Andomar
@KM,这非常好!谢谢!我也需要在我的一个项目中使用它,因为我在生产环境中遇到了死锁问题。 - nolisj
显示剩余2条评论

0

您可以在开发环境中运行分析器跟踪查询,以查看确切的锁定情况。这通常是大量数据,但其中许多都是您可以快速浏览的模式。例如,在读提交隔离级别下,当您执行表或索引扫描时,您将看到一系列被获取和释放的锁定(每个行在读取之前必须被锁定,并且在读取后立即释放)。

您使用哪种隔离级别?哪些查询导致死锁?您是否使用涵盖多个更新的显式事务,还是单个语句死锁?

死锁最典型的情况是一个序列为(更新表x,更新表y)的事务,以及一个序列为(更新表y,更新表x)的第二个事务。常见的解决方案是确保在查询中使用相同的更新序列。

请告诉我们它们是什么类型的查询,因为不同类型的事务存在不同的常见问题。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接