Stored procedures SQL Server事务阻塞之谜

Stored procedures SQL Server事务阻塞之谜,stored-procedures,sql-server-2012,transactions,blocking,Stored Procedures,Sql Server 2012,Transactions,Blocking,我有一个用于表单处理的.Net应用程序,它可以跨三个不同的SQL Server 2012数据库删除/更新/插入数据。当应用程序运行时,它会打开一个数据上下文,然后在该上下文中为每个需要处理的表单打开一个事务。该事务每分钟运行一次,因此通常一次只运行一个表单。在这个事务中会发生很多事情,包括多个存储过程调用 问题是: 我们已经用我被告知的完全相同的规格设置了服务器,尽管我对此表示怀疑:。一个用于开发工作;另一个用于客户端测试。在我们的开发环境中,处理运行没有问题;但是在客户端测试站点上,它每次都挂

我有一个用于表单处理的.Net应用程序,它可以跨三个不同的SQL Server 2012数据库删除/更新/插入数据。当应用程序运行时,它会打开一个数据上下文,然后在该上下文中为每个需要处理的表单打开一个事务。该事务每分钟运行一次,因此通常一次只运行一个表单。在这个事务中会发生很多事情,包括多个存储过程调用

问题是:

我们已经用我被告知的完全相同的规格设置了服务器,尽管我对此表示怀疑:。一个用于开发工作;另一个用于客户端测试。在我们的开发环境中,处理运行没有问题;但是在客户端测试站点上,它每次都挂起。我正在努力找出原因

在下面的TSQL代码中,插入参数表失败。除了列名之外,Param表本质上与Method表相同。这两个插入都与表单表具有类似的外键关系,并且都将int值插入ID列

当我运行SQL Server Profiler时,我被告知FormDB上有一个锁,不允许插入。但是,我可以更改Param insert的select语句,它可以正常工作。我已通过以下方式进行了更改,所有这些方式都在某种意义上起作用,即它们不会导致阻塞问题:

将Param select替换为方法select,同时将insert保留为Param.defs与Param select完全相同的列defs 将@newKey替换为现有表单的有效整数。 删除了参数select的部分,并为参数select@newKey,1,@modifyDate,@modifyUser硬编码了一个int值 我觉得我疯了,因为我不明白为什么它不起作用。只有当select语句中的三个内容组合为@newKey、ParamID和from语句时,插入才会失败

我已经确保每个存储过程都将事务隔离级别设置为readuncommitted,并在必要时与nolock一起使用

为什么我可以通过上述三种方案成功地插入到Param表中,但在下面的代码中插入Param失败?为什么我不能在探查器中收到相同的锁消息?在此过程中,大约有5个其他插件遵循相同的模式。所有这些工作都没有问题

有什么想法吗?谢谢

USE [PROD]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[HELPSPROC]
    @oldKey int 
AS

BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    declare @newKey int
    , @spKey int
    , @modifyDate datetime = getdate()
    , @modifyUser varchar(30) = 'User'

/*
a bunch of stuff happens here, including setting the @spKey value. 
this all happening correctly -- we have a valid integer value when we go into the next part
*/

---------------FORM---------------
INSERT INTO FormDB.dbo.Form
    (formtype, formstatus, modifydate, modifyuser)
Select 
    'TestFormType', 'DRAFT', @modifyDate, @modifyUser                            
From FormDB2.dbo.Form f  
Where f.Pkey = @oldKey

--grab the new int identifier -- works                     
set @newKey = (select scope_identity())

/*
stuff happens here. all is good in this part
*/


---------------Param---------------
INSERT INTO  FormDB.dbo.Param
    (FormKey, ParamID, ModifyDate, ModifyUser) 
select @newKey, p.ParamID, @modifyDate, @modifyUser
from PROD.dbo.Table1 apd 
    inner join PROD.dbo.ParameterTable p 
        on apd.TableTwoKey = p.TableTwoKey
where apd.PKey = @spKey



---------------Method---------------
INSERT INTO  FormDB.dbo.Method
    (FormKey, MethodID, ModifyDate, ModifyUser) 
select @newKey, r.MethodID, @modifyDate, @modifyUser
from PROD.dbo.Table1 apd 
    inner join PROD.dbo.MethodTable r 
        on apd.TableTwoKey = r.TableTwoKey
where apd.PKey = @spKey

/*
one more insert ...
*/


RETURN 1

END

GO

我仍然不明白这个问题的原因,但我找到了解决办法

在这个过程的vb.net代码中发生了很多事情:在三个独立的数据库中进行多个linq到sql的插入/删除/更新,以及两个独立的存储过程调用。为了增加这种混乱,每个数据库都有单独的上下文声明,每个上下文都有自己的事务。简而言之,一堆活动部件

第二个存储过程调用是有条件的,基于处理表单的某些值。我只是从vb.net代码中提取了这个调用,并将条件逻辑和存储的过程调用放在第一个过程中。这就解决了问题。第二个存储过程是在第一个条件(挂起条件)之后直接调用的,因此一切正常


问题解决了——但如果有人能解释为什么会发生这种情况,我将不胜感激。谢谢

你说FormDB上有锁是什么意思?嗨,Alex。从我使用SQL事件探查器、活动监视器和以下存储过程获得的详细信息中,我可以看到一个SPID(状态为休眠,正在等待命令)正在阻止另一个SPID上的当前插入状态为挂起。我猜:您可能在某处有未提交的事务。如果使用链接服务器,请检查“启用分布式事务升级”设置是否相同。太好了。谢谢你的提示@Alex!