流行表上的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