我们有一个用 C# 建立异步数据库连接的应用程序,它尝试同时运行两个
SELECT
语句。两个语句都引用相同的临时表,但只是SELECT
,但我们看到发生死锁和操作错误。
死锁图表明双方具有相同的 SPID,并显示它正在尝试获取 tempdb 对象(临时表)上的独占锁。在旧版本的 SQL Server 中,相同数据上的相同代码可以工作,但在测试迁移到 SQL Server 2019 时,我们发现死锁导致应用程序中出现错误。通过全局启用跟踪标志 1204 和 1222 确定导致死锁的对象是临时表。
来自SQL错误日志:
objectlock lockPartition=0 objid=-1598015006 subresource=FULL dbid=2 objectname=tempdb.dbo.#TempTable__________________________________________________________________________________________________________0000000049FC id=lock219d47a4c80 mode=X associatedObjectId=-1598015006
当我们更改 C# 以串行方式进行调用(无异步)时,不会出现错误 - 这是有道理的,因为没有对同一 tempdb 对象的并发访问。
在旧的 SQL 版本中,我们没有死锁。两个实例之间唯一明显的区别是 SQL Server 版本。将 mdf/ldf 从 SQL Server 2016 实例复制到 SQL Server 2019 实例并附加。两者的兼容性级别相同。
编辑:死锁 XML 报告
<deadlock>
<victim-list>
<victimProcess id="process21a00a2b848" />
</victim-list>
<process-list>
<process id="process21a00a2b848" taskpriority="0" logused="0" waitresource="OBJECT: 2:-1346206128:0 " waittime="2837" ownerId="25719004" transactionname="SELECT" lasttranstarted="2024-01-12T10:19:32.853" XDES="0x21568dce188" lockMode="X" schedulerid="13" kpid="10232" status="suspended" spid="147" sbid="2" ecid="0" priority="0" trancount="0" lastbatchstarted="2024-01-12T10:19:32.817" lastbatchcompleted="2024-01-12T10:19:31.813" lastattention="1900-01-01T00:00:00.813" clientapp=".Net SqlClient Data Provider" hostname="HOSTMACH1" hostpid="11172" loginname="DOMAIN1\Account1" isolationlevel="read committed (2)" xactid="25719004" currentdb="6" currentdbname="TestDB1" lockTimeout="4294967295" clientoption1="671088928" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="2" stmtstart="838" stmtend="6934" sqlhandle="0x020000008e6ea223919a9751bfa1ae026e9f70a4edb236af0000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@Var0 nvarchar(36),@Var1 nvarchar(36),@Var2 nvarchar(36),@Var3 nvarchar(36),@Var4 nvarchar(36),@Var5 nvarchar(36),@Var6 nvarchar(36),@Var7 nvarchar(36),@Var8 nvarchar(36),@Var9 nvarchar(8),@Var10 nvarchar(8),@Var12 nvarchar(9),@Var11 nvarchar(8),@Var13 decimal(5,2),@Var14 uniqueidentifier)
SELECT ID1, Val1,CASE WHEN Date1 is NULL then Date2 ELSE Date1 END as displayDate, Date2, Val2,Val0,Val3,Val4, Val5, Val6, Val7, Val8, Val9, isnull(Val10,0) as Val10, isnull(Val11,0) as Val11, #TempTable1.Val12 Val12, '' as Val13,
table1.* , Val14, Val15 as Val15
,substring(convert(varchar(36),ID1),0,23) as TransID, substring(convert(varchar(36),val </inputbuf>
</process>
<process id="process21a00a43c28" waittime="2874" schedulerid="16" kpid="2816" status="suspended" spid="147" sbid="2" ecid="0" priority="0" trancount="0" lastbatchstarted="2024-01-12T10:19:32.817" lastbatchcompleted="2024-01-12T10:19:31.813" lastattention="1900-01-01T00:00:00.813" clientapp=".Net SqlClient Data Provider" hostname="HOSTMACH1" hostpid="11172" loginname="DOMAIN1\Account1" isolationlevel="read committed (2)" xactid="25719004" currentdb="6" currentdbname="TestDB1" lockTimeout="4294967295" clientoption1="671088928" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="2" stmtstart="838" stmtend="6934" sqlhandle="0x020000008e6ea223919a9751bfa1ae026e9f70a4edb236af0000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@Var0 nvarchar(36),@Var1 nvarchar(36),@Var2 nvarchar(36),@Var3 nvarchar(36),@Var4 nvarchar(36),@Var5 nvarchar(36),@Var6 nvarchar(36),@Var7 nvarchar(36),@Var8 nvarchar(36),@Var9 nvarchar(8),@Var10 nvarchar(8),@Var12 nvarchar(9),@Var11 nvarchar(8),@Var13 decimal(5,2),@Var14 uniqueidentifier)
SELECT ID1, Val1,CASE WHEN Date1 is NULL then Date2 ELSE Date1 END as displayDate, Date2, Val2,Val0,Val3,Val4, Val5, Val6, Val7, Val8, Val9, isnull(Val10,0) as Val10, isnull(Val11,0) as Val11, #TempTable1.Val12 Val12, '' as Val13,
table1.* , Val14, Val15 as Val15
,substring(convert(varchar(36),ID1),0,23) as TransID, substring(convert(varchar(36),val </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="-1346206128" subresource="FULL" dbid="2" objectname="tempdb.dbo.#TempTable1__________________________________________________________________________________________________________00000000469C" id="lock217a1a7a080" mode="X" associatedObjectId="-1346206128">
<owner-list>
<owner id="process21a00a43c28" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process21a00a2b848" mode="X" requestType="wait" />
</waiter-list>
</objectlock>
<TransactionMutex>
<TransactionInfo Workspace="2308500986304" />
<owner-list>
<owner id="process21a00a2b848" />
</owner-list>
<waiter-list>
<waiter id="process21a00a43c28" />
</waiter-list>
</TransactionMutex>
</resource-list>
</deadlock>
此问题已通过将 SQL Server 2019 更新到最新的累积更新来解决。 SQL Server 错误可能导致该问题并在更新后得到解决。
仅供参考,它似乎已在 CU 19 中解决:https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2019/cumulativeupdate19#2162840