【发布时间】:2017-12-28 17:20:10
【问题描述】:
我有一个用于表单处理的 .Net 应用程序,它可以跨三个不同的 SQL Server 2012 数据库删除/更新/插入数据。当应用程序运行时,它会打开一个数据上下文,然后在该上下文中为需要处理的每个表单打开一个事务(这每分钟运行一次,因此通常一次不超过一个表单)。在这个事务中发生了很多事情——包括多个存储过程调用。
那么问题来了:
我们设置的服务器与我被告知的规格完全相同(尽管我很怀疑 :))。一个用于开发工作;另一个用于客户端测试。在我们的开发环境中,处理运行没有问题;但是在客户端测试站点上,它每次都挂起。我正在拔头发试图确定原因。
在以下 TSQL 代码中,失败是插入到 Param 表中。 Param 表与 Method 表基本相同,除了列名。两次插入都与 Form 表具有相似的外键关系,并且都将 int 值插入到 ID 列中。
当我运行 SQL Server Profiler 时,我被告知 FormDB 上有一个不允许插入的锁。但是,我可以更改 Param 插入的 select 语句,它可以工作。我已经通过以下方式进行了更改,所有这些方式都“有效”,因为它们不会导致阻塞问题:
- 将参数选择替换为方法选择,同时保留对参数的插入。(与参数选择完全相同的列定义)
- 将@newKey 替换为现有表单的有效整数。
- 删除了 Param 选择的“from”部分并硬编码了 paramID 的单个 int 值(即选择 @newKey、1、@modifyDate、@modifyUser)
我觉得我疯了,因为我不明白为什么它不起作用。只有当三个东西都在 select 语句中时,插入似乎才会失败——@newKey、ParamID 和 from 语句。
我已确保每个 sproc 都设置了 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 并在必要时使用了 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
【问题讨论】:
-
“FormDB 上有锁”是什么意思?
-
嗨@Alex。从我使用 SQL Profiler、Activity Monitor 和来自Microsoft 的以下存储过程中获得的详细信息中,我可以看到一个 SPID(状态处于睡眠状态并等待命令)正在阻止另一个 SPID 上的当前插入(状态暂停)。
标签: stored-procedures sql-server-2012 transactions blocking