Sql-Server
主鍵列並發更新導致死鎖
我有一個簡單的表 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 列進行比較會阻止使用主鍵索引來定位行,從而導致完全掃描,從而導致活動系統上的阻塞和死鎖。