流行表上的SQL Server锁定问题
我遇到了一个问题,我需要更清醒的头脑来思考。有时,此存储过程(以及许多其他类似的存储过程)会: 将尝试将流行表上的SQL Server锁定问题,sql,sql-server,locking,Sql,Sql Server,Locking,我遇到了一个问题,我需要更清醒的头脑来思考。有时,此存储过程(以及许多其他类似的存储过程)会: 将尝试将null插入original\u rec,该列不允许空值。表是\u clientindex是一个非常繁忙的表,正在进行大量读取。很少插入或更新 我认为发生的情况是,is\u clientindex被锁定,或者以其他方式不可用。这会导致选择失败,最终导致插入失败 听起来我是不是走对了方向 我是否应该对Is_clientindex做些什么来帮助解决这个锁定问题?该表/数据库将使用SQL Serve
null
插入original\u rec
,该列不允许空值。表是\u clientindex
是一个非常繁忙的表,正在进行大量读取。很少插入或更新
我认为发生的情况是,is\u clientindex
被锁定,或者以其他方式不可用。这会导致选择失败,最终导致插入失败
听起来我是不是走对了方向
我是否应该对Is_clientindex做些什么来帮助解决这个锁定问题?该表/数据库将使用SQL Server 2005默认值创建以进行锁定
我是否应该对此存储过程执行任何操作
不幸的是,在插入此表时,我确实需要检查中的updated
标志是否为\u clientindex
。这是没有办法的
编辑:
- @ClientID是有效的(我们通过调试知道这一点),并且is_clientindex表是系统中所有其他内容的外键,因此我们知道它没有消失
- 这仅在多个用户的重载情况下发生
- 活动监视器显示了很多页面锁,但我不知道是什么,因为对象ID与sys.all_objects表中的任何内容都不对应
- 锁定与此无关
选择
s仅在表上放置相互兼容的共享锁
如果您没有对您的表发出DML
,则SELECT
将永远不会相互阻塞
即使发生锁争用,SELECT
也只会等待并发锁被释放,并且只有当@@lock\u TIMEOUT
设置为大于0
的值并且超时发生时,SELECT
才会失败
在这种情况下,它将报告一个错误
如果在中没有具有给定@ClientID
的记录是\u clientindex
,或者更新的的值是NULL
,则选择
查询将@s
设置为NULL
将您的插入查询更改为:
INSERT
INTO is_address1 (original_rec, clientID, street,city,state,zip)
SELECT updated + 1, @clientID, @street, @city, @state, @zip
FROM is_clientindex
WHERE clientid = @clientID
AND updated IS NOT NULL
可能只是因为is_clientindex表没有给定clientid的记录(@clientid参数来自何处?)和/或此类记录的xxx值实际上为空
如果是锁定情况,选择只需“很长时间”即可完成,但不会返回NULL
编辑:(根据托梅茨帕科维奇的精明评论)
“返回空值”是对现实的一种相当松散的描述。返回“NULL”的唯一情况是,实际上找到了一条记录,并且基础列的值为NULL。如果出现错误(可能是超时、连接错误等),则无法分配变量。
这就是为什么人们应该系统地检查错误,正如托梅克斯·帕科维奇自己的回答中所建议的那样
通过将更新查询更改为“FROM”表单,您还可以在一次到SQL server的过程中执行更新,这更高效,并且可能有助于锁定情况。当第一次选择由于锁定或超时而失败时,整个存储过程将中止
问题可能是并非所有客户端都在is_clientindex中有一行。通过在过程的开头添加以下SQL,可以确保行存在。如果没有,这将创建一行:
insert into is_clientindex (clientid, updated)
select @clientid,0
where not exists (
select * from where clientid = @clientID
)
对于第二部分,Quassnoi的单语句方法是一个非常好的主意。读卡器不会阻止读卡器,因此如果很少在is\u clientindex上插入和更新,则此表上不会有争用。即使选择超时,它也不会默默地执行(有人真的通过设置SET LOCK\u TIMEOUT来允许选择超时吗?)
我的猜测是,有时clientid不存在,这是一种会导致@s不被修改并保留其NULL值的条件
顺便说一句,使用scope_identity()而不是@@identity。默认情况下,SQL Server会忽略T-SQL块中的错误,并尝试继续。因此,这完全取决于您如何使用事务:
- 若您自己在T-SQL中管理事务,那个么您需要在那个里检测错误并执行回滚
- 如果事务是通过调用应用程序(显式地或通过每个语句的自动事务)来管理的,则在向应用程序报告错误后,可以将事务回滚到该应用程序
在SQL Server 2005或更新版本中,在过程主体周围使用TRY…CATCH块来处理锁定超时错误
在SQLServer2000中,您应该这样做
IF @@error <> 0 goto ON_ERROR
IF@@error 0转到\u错误
或者在每一个可能失败的陈述之后都会出现类似的情况。这也适用于较新的版本,但对于锁定超时等错误的处理要多得多
设置锁定超时将没有帮助。如果SQL Server检测到实际的死锁(与长时间等待锁定相反),它仍将引发错误
更可能是逻辑错误-@s在查询后为null。
如果发生错误,您可以自己添加check和RAISERROR。
只是想确定一下。
这就像普通编程语言中的assert()。您仍然需要处理它,但可以将INSERT嵌套在IF中,例如“IF@s不是null”。这将防止插入失败,因此没有例外。但您仍然存在一个问题,即您没有执行插入。没有人提到您使用了@IDENTITY;使用SCOPE_IDENTITY()来代替…@clintp:是的,它仍然是错误的。事实上,我知道这是一种可能性。不管系统其余部分的设计方式如何,记录仍然存在。通过调试,我们知道@ClientID是正确的,并且是foreig
IF @@error <> 0 goto ON_ERROR