我在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个选定行上应用更新时,另一个进程正在选择下一个组,并获取第一组尚未更新的某些记录(因为行锁)。这可能吗?
非常感谢任何帮助!
答案 0 :(得分:1)
是的,这听起来不错。您可以通过将整个操作放在可序列化事务中来修复它(以丢失并发为代价)。这将保证所有行在事务的生命周期中被锁定,而不是仅在原子行级读取和更新期间。
答案 1 :(得分:0)
我相信这种情况正在发生,因为SQL Server正在将行级锁升级为页锁。您认为在其中指定主键的UPDATE总是会导致行锁定,但是当SQL Server获得一堆具有这些的批处理时,其中一些恰好位于同一页面中(取决于这种情况) ,这很可能,例如更新文件夹中的所有文件,几乎同时创建的文件),你会看到页面锁定,并且会发生不好的事情。如果你没有为UPDATE或DELETE指定一个主键,那么数据库就没有理由不会认为很多东西不会受到影响,所以它可能正好用于页面锁定,并且会发生不好的事情。
通过专门请求行级锁定,可以避免这些问题,但是,在您的情况下,许多行都会受到影响,并且数据库正在采取主动并升级为页锁。