Sql-Server

主鍵列並發更新導致死鎖

  • March 20, 2021

我有一個簡單的表 T,它有 Col1、Col2、Col3 和 Col4。列。Col1 是主鍵。現在我正在執行一些並發程式碼,

Parallel.For(0, list.Count, new ParallelOptions { MaxDegreeOfParallelism = -1 }, j =>
{
  var obj= list[j];
  // Do some work
  // UPDATE T SET Col2, Col3, Col4 WHERE Col1 =@Col1

col1 的每個值都是不同的。但是當我執行這段程式碼時,我遇到了太多的死鎖。由於 Col1 是 PK(聚集索引),我現在很困惑為什麼會這樣?

陷入僵局。我看到所有者模式:U

每當我跑步時,

USE master
GO
DROP TABLE temp_sp_who2
GO
CREATE TABLE temp_sp_who2 ( SPID INT, Status VARCHAR(1000) NULL, Login SYSNAME NULL, HostName SYSNAME NULL, BlkBy SYSNAME NULL,DBName SYSNAME NULL,Command VARCHAR(1000) NULL, CPUTime INT NULL,DiskIO BIGINT NULL,  LastBatch VARCHAR(1000) NULL, ProgramName VARCHAR(1000) NULL,SPID2 INT , RequestId INT NULL )
GO

INSERT  INTO temp_sp_who2
EXEC sp_who2

SELECT  BlkBy ,count(*) FROM 
temp_sp_who2 WHERE CAST(BlkBy AS NVARCHAR(MAX)) <> CAST(SPID AS NVARCHAR(MAX)) 
GROUP By BlkBy
ORDER BY Count(*) DESC
GO

我看到 BlkBy 與高數字不同。但是當應用程序執行時,BlkBy 總是很高。

沒有死鎖痕跡,我們只能根據症狀進行猜測。

長期阻塞和死鎖表明單例行更新查詢正在執行完整掃描,而不是通過 PK 索引定位行。如果主鍵參數數據類型與引用的列不同,並且導致無法有效使用 PK 索引的非 sargable 表達式,則會發生這種情況。

在應用程式碼或儲存過程中聲明參數時注意細節很重要,以確保參數定義與引用的列類型匹配。ADO.NET 中類型不匹配(不一定是您的類型)的常見原因是AddWithValue方法,它根據提供的值推斷 SQL 類型。.NET 中的字元串是 Unicode,因此字元串值的結果參數類型是nvarchar. 將 nvarchar 參數與舊的 SQL 排序規則 varchar 列進行比較會阻止使用主鍵索引來定位行,從而導致完全掃描,從而導致活動系統上的阻塞和死鎖。

引用自:https://dba.stackexchange.com/questions/287393