如何防止 SELECT 查询出现死锁?

SHR*_*SHR 4 sql-server deadlock

我有一个多会话数据库。很少有会话将多行插入到数据库中。并且一个会话从此表中选择。

有时我在 SELECT 查询上遇到死锁,我不明白为什么。

例如:假设这个表

Create Table t1([id] int identity(1,1), [column] varchar(max))
Run Code Online (Sandbox Code Playgroud)

插入是这样的:(我是从“之后”触发器中进行的)

Begin Transaction
Insert into t1 WITH (TABLOCKX) ([column]) values ('value 1'), ('value 2') ... ('value N')
Commit Transaction
Run Code Online (Sandbox Code Playgroud)

选择是这样的:

Select TOP 10 [id],[column] from t1 order by id
Run Code Online (Sandbox Code Playgroud)

对插入的锁定意味着在 DB 中保持会话插入的顺序。

每次我在一个事务中只锁定一张表。我试图通过一个会话插入和第二个会话来恢复僵局,但我失败了。在我添加 TABLOCKX 之前,我从未遇到过僵局。

所以我的问题是:

  1. 为什么会出现死锁?(也许在嵌套事务中?)
  2. MSSQL 中是否有一个选项可以以不阻止选择的方式进行写锁定?
  3. 有什么想法可以防止死锁吗?(但保持数据库中的会话插入顺序不变......)

小智 7

如果没有查询或死锁图,我无法对您的死锁说太多。
您是否有任何理由指定排他表锁?
SQL Server 非常擅长将锁从行或页升级到表本身。

MSSQL 中是否有一个选项可以以不阻止选择的方式进行写锁定?

是的,您可以启用READ COMMITTED SNAPSHOT ISOLATION LEVEL
使用此隔离级别,您始终可以读取已提交的内容。如果此时正在写入另一个查询,您将看到所写入内容的最新快照。
请通读 MSDN 页面,看看 RCSIL 是否适用于您的应用程序。