同一记录上的并发更新

时间:2009-09-30 13:00:48

标签: sql-server tsql

我在SQL2005上面临一些奇怪的问题。

我们怀疑产生问题的一件事是:

INSERT INTO SGVdProcessInfo
    ([StartTs])
    VALUES
    (GETDATE())

SELECT @IdProcessInfo = SCOPE_IDENTITY()

UPDATE TOP(@quantity)
    [SGVdTLogDetail] WITH (ROWLOCK)  
SET 
    [IdSGVdProcessInfo] = @IdProcessInfo
WHERE 
    [IdSGVdProcessInfo] IS NULL
    and IdTLogDetailStatus != 9 

@quantity通常需要500。

在SGVdTLogDetail上的IdSGVdProcessInfo和IdTLogDetailStatus上有一个非聚集索引

正在发生的事情是SGVdTLogDetail的某些记录首先使用processinfo表的一个id进行更新,然后由另一个具有新processinfo ID的进程再次更新。

我想知道行锁提示是否引发了这个问题,或者是否还有其他问题......

我的猜测是,在前500个选定行上应用更新时,另一个进程正在选择下一个组,并获取第一组尚未更新的某些记录(因为行锁)。这可能吗?

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

是的,这听起来不错。您可以通过将整个操作放在可序列化事务中来修复它(以丢失并发为代价)。这将保证所有行在事务的生命周期中被锁定,而不是仅在原子行级读取和更新期间。

答案 1 :(得分:0)

我相信这种情况正在发生,因为SQL Server正在将行级锁升级为页锁。您认为在其中指定主键的UPDATE总是会导致行锁定,但是当SQL Server获得一堆具有这些的批处理时,其中一些恰好位于同一页面中(取决于这种情况) ,这很可能,例如更新文件夹中的所有文件,几乎同时创建的文件),你会看到页面锁定,并且会发生不好的事情。如果你没有为UPDATE或DELETE指定一个主键,那么数据库就没有理由不会认为很多东西不会受到影响,所以它可能正好用于页面锁定,并且会发生不好的事情。

通过专门请求行级锁定,可以避免这些问题,但是,在您的情况下,许多行都会受到影响,并且数据库正在采取主动并升级为页锁。