休眠的SPID阻止了其他事务


16

我确实很难找到我们遇到的一些障碍。

根阻止SPID的状态为“正在休眠”,cmd为“正在等待命令”,并且sqltextSET TRANSACTION ISOLATION LEVEL READ COMMITTED

当我查看“按阻塞的交易计数列出的最高交易”报告时,阻塞的SQL语句为“-”。

我已经在SQL上执行了跟踪,并且当阻塞发生时是在跟踪根阻塞SPID,但它并没有真正引导我到任何地方。最后一个trace语句与sqltext上面的相同SET TRANSACTION ISOLATION LEVEL READ COMMITTED

我检查了所有可以找到的相关存储过程,以确保它们具有TRY / CATCH BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN语句(我们将存储过程用于所有内容,因此没有独立的语句在运行)。该问题在过去的24小时内才刚刚开始发生,并且没有人声称对系统进行了任何更改。

解决方案:我们很少使用的存储过程之一有一个插入错误(列数不匹配),但是我们仍然对正在发生的事情感到困惑。

查看所有跟踪信息时,有时会列出该存储过程的EXEC语句,但绝不会在阻塞SPID上发生BLOCK之前。看来,当它开始阻塞时,跟踪并没有记录它(或其中的任何一条语句)的执行情况。但是,还有其他时间跟踪确实记录了它的执行并且没有发生阻塞。

存储过程错误报告来自用户,我能够在跟踪中找到多个EXEC语句并在SSMS中运行它们。当我运行它们时,我们没有任何阻塞发生或挂起的情况。它们按预期运行(错误后触发catch块并回滚了事务)。解决了存储过程的问题后,我们再也没有看到此问题。


我假设阻塞的SPID的主机名根本没有帮助?
乔恩·塞格尔

不,这只是我们其中一个Web服务器的IP地址...我们还有另一种想法,就是在登录/注册过程(我们认为是发生错误的地方)中,将每个SPROC调用的每个SQL登录名更改为一个单独的用户名帮助我们找出可能引起阻塞的SPROC。
布拉德,

1
TRY / CATCH将不会捕获编译错误,并且不匹配的列插入将是这样的编译错误。这也永远不会触发许多XX:Completed事件探查器事件。
Remus Rusanu

1
在这种情况下,这实际上不是编译错误,因为天才开发人员使用了[othertable]中的INSERT INTO [table] SELECT *,并且没有陷入同行。我在3个同时的会话中从ColdFusion运行了1000次开发中的SPROC,它从未像在生产中那样打开过任何事务。
布拉德,

Answers:


10

从注释中,我猜测您的客户端Command超时已中止SQL查询。这不会回滚事务,因为由于连接池的原因,连接在SQL Server上保持打开状态。

因此,您需要使用SET XACT_ABORT ON或添加一些客户端回滚代码

有关所有详细信息,请参见SQL Server事务超时


我们所有的SPROC都包含TRY / CATCH块和BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN语句,ROLLBACK在CATCH中。XACT_ABORT仍然会起作用吗?
布拉德,

@布拉德:是的。看到我的链接。在CommandTimeout上未击中catch块
gbn

gbn:谢谢。我还是很困惑。我们的连接设置为永不超时(0)。因此,您说的是,如果我们重复使用连接,并且连接运行的SPROC出现错误(具有TRY / CATCH和TRAN块),则它永远无法以某种方式在CATCH块中运行ROLLBACK从而锁定表并保持事务打开?这对我来说没有意义。
布拉德,

@Brad:出现错误的SPROC将命中CATCH块。我没有说其他或不同的。但是我的链接说明了如果您有一个CommandTimeout(与ConnectionTimeout不同)会发生什么。客户端说“中止”,SQL Server停止处理。因此,从未遇到过CATCH块,回滚或提交
-gbn

我认为我们没有指定CommandTimeout。我们所有的存储过程都使用sqlstress进行测试,并且必须在1000ms内以10个用户执行10次迭代(至少)。我对发生的事情仍然很困惑,但是我用发现的问题更新了这个问题。
布拉德,

9

使用sys.dm_exec_connections中的most_recent_sql_handle查看最后执行的语句。

SELECT  t.text,
        QUOTENAME(OBJECT_SCHEMA_NAME(t.objectid, t.dbid)) + '.'
        + QUOTENAME(OBJECT_NAME(t.objectid, t.dbid)) proc_name,
        c.connect_time,
        s.last_request_start_time,
        s.last_request_end_time,
        s.status
FROM    sys.dm_exec_connections c
JOIN    sys.dm_exec_sessions s
        ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t
WHERE   c.session_id = 72;--your blocking spid

还要检查该spid是否有未完成的交易

SELECT  st.transaction_id,
        at.name,
        at.transaction_begin_time,
        at.transaction_state,
        at.transaction_status
FROM    sys.dm_tran_session_transactions st
JOIN    sys.dm_tran_active_transactions at
        ON st.transaction_id = at.transaction_id
WHERE   st.session_id = 72;--your blocking spid

您还可以DBCC INPUTBUFFER(spid)用来查看最后执行的SQL。
Mike Fal

我已经使用了所有这些命令,最后一个命令始终是我在原始帖子中输入的内容:SET TRANSACTION ISOLATION LEVEL READ COMMITTED。我还运行了DBCC OPENTRAN,可以看到阻塞的PID有一个打开的事务。
布拉德

如果该语句确实是过程的一部分,则我的第一选择还为您提供过程名称。
塞巴斯蒂安·梅因

我向您保证,我们不使用来自Web服务器的特别查询,当我运行第一个查询时,即使没有WHERE子句,我在少数SQL会话中也只能得到命名的SPROC,该列的其余部分为NULL。
布拉德

我确实注意到,我有很多会话都说“ SET TRANSACTION ISOLATION LEVEL READ COMMITTED”,并且所有会话都来自ColdFusion(我们Web服务器上使用的主要脚本)。闲置时,也许ColdFusion发出该语句来保持打开连接(因为它设置为保持连接打开)。
布拉德,

4

您是否尝试过使用Adam Machanic的sp_whoisactive?有一个选项可以使外部命令查看它是否真的在proc中。可能是应用程序正在保持打开事务而不是提交事务。也尝试查看DBCC OPENTRAN


感谢DBCC OPENTRAN。它确实告诉我阻塞的PID有一个未完成的事务,但是没有更多详细信息可用。sp_whoisactive在阻塞进程中返回的信息与我自己获得的信息相同。除了“ SET TRANSACTION ISOLATION LEVEL READ COMMITTED”以外,没有任何其他细节
布拉德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.