使用 XLOCK 和 ROWLOCK 时 SQL Server 2008 的奇怪行为

Ari*_*ian 6 sql-server-2008 sql-server

我在没有COMMIT新查询窗口 (Query1) 的情况下编写了这个脚本:

BEGIN TRAN
SELECT [RegionID], [RegionDescription]
FROM [Northwind].[dbo].[Region] WITH(XLOCK,ROWLOCK)
WHERE RegionID = 3 
Run Code Online (Sandbox Code Playgroud)

在另一个查询窗口中,我在没有 COMMIT (Query2) 的情况下编写了这个脚本:

BEGIN TRAN 
SELECT [RegionID], [RegionDescription]
FROM [Northwind].[dbo].[Region] WITH(XLOCK,ROWLOCK)
WHERE RegionID = 1 
Run Code Online (Sandbox Code Playgroud)

一切正常,当我运行 Query1 然后 Query2 时,我可以选择带有RegioID=1. 但是如果我这样写第一个查询(Query3):

BEGIN TRAN
SELECT [RegionID], [RegionDescription]
FROM [Northwind].[dbo].[Region] WITH(XLOCK,ROWLOCK)
WHERE RegionID = 3 OR RegionID = 4
Run Code Online (Sandbox Code Playgroud)

...并添加RegionID = 4结果,我无法运行 Query2。为什么 Query2 结果没有与 Query3 相交我不能运行它?

gbn*_*gbn 4

第三个查询有一个 OR,这很可能意味着正在进行扫描。扫描将被阻止RegionID = 1

如果你运行这个,它应该运行正常。

BEGIN TRAN
SELECT [RegionID], [RegionDescription]
FROM [Northwind].[dbo].[Region] WITH(XLOCK,ROWLOCK)
WHERE RegionID = 4

SELECT [RegionID], [RegionDescription]
FROM [Northwind].[dbo].[Region] WITH(XLOCK,ROWLOCK)
WHERE RegionID = 3
Run Code Online (Sandbox Code Playgroud)

另一种方法是您仍然有查询 1 事务处于打开状态...

编辑:

我无法重现它(SQL Server 2008 R2 x64 开发人员)。我在查询 3 上得到了索引查找。

然而,在我的第一次迭代中,我忘记了表上的主键,并且 query1 阻止了 query2,因为它是表扫描。这主要支持了我上面的答案

编辑2:

我无法让查询 2 或查询 3 互相阻塞(无论哪个先运行)

评论后:

  • 扫描为每个扫描行放置一个 XLOCK
  • OR 通常是不可定位的:AND 就可以。(或者有一些优化