2015-11-30 130 views
0

一些背景信息:
通過刪除舊數據並插入新數據來定期更新數據。 數據被聚集到配置文件中,我將其用作主鍵的一部分,並用於刪除舊數據。
只有一個進程寫入數據,所以不必擔心別人更新衝突。
其他進程只讀取我計劃通過快照隔離解決的數據。
我通過實體框架6訪問數據,代碼優先建模。SQL並行刪除鎖定

問題: 我開始收集幾個並行的配置文件的數據。適用於所有使用簡單外鍵關係但具有自引用關係的表格。

public class Web 
{ 
    public Web() 
    { 
     CacheDate = DateTime.Now; 
    } 

    [Key, Column(Order = 0)] 
    public Guid ProfileGuid { get; set; } 
    [Key, Column(Order = 2)] 
    public Guid WebId { get; set; } 

    public string Data { get; set; } 

    public virtual List<List> Lists { get; set; } 
    public virtual List<Web> SubWebs { get; set; } 

    public Guid? ParentProfileGuid { get; set; } 
    public Guid? ParentWebId { get; set; } 

    public virtual Web ParentWeb { get; set;} 
} 

modelBuilder.Entity<CacheWeb>() 
    .HasMany(e => e.SubWebs) 
    .WithOptional(e => e.ParentWeb) 
    .HasForeignKey(e => new { e.ParentProfileGuid, e.ParentWebId }) 
    .WillCascadeOnDelete(false); 

由於性能問題,我不使用EF刪除數據,但自定義SQL命令:InsertContext.Database.ExecuteSqlCommand(String.Format("DELETE FROM Webs WHERE ProfileGuid = '{0}'", profile.Guid));

如果我叫兩個併發事務這些刪除的,在第一次調用創建一個鎖,阻止第二筆交易繼續。

據我所知,該鎖以某種方式連接到自我引用的索引。

我剛發現另一個奇怪的行爲,它取決於哪個事務先刪除。 我可以找到的數據唯一的區別是父子關係的深度。
如果我先運行事務A(有一個父節點和幾個直接子節點),事後我不能運行事務B(有一些父 - >子 - >子節點關係),但是如果我先運行B,用現有的鎖進入麻煩。

有沒有辦法解決這個問題?或者有什麼想法可能是鎖的問題? 如果您需要更多信息,請評論您的需求,因爲我不確定什麼是重要的。

編輯:澄清

BEGIN Transaction t1 
DELETE FROM Webs WHERE ProfileGuid = 'b35dbba4-54fc-4df7-b1c8-e559d81dfee3' 
BEGIN Transaction t2 
DELETE FROM Webs WHERE ProfileGuid = 'b35dbba4-54fc-4df7-b1c8-e559d81dfee4' 

作品。交換訂單,t1必須等待t2完成。

EDIT2:執行計劃 Seek Scan

EDIT3:型號和完整查詢 model_s 執行計劃是從第三查詢(CacheList的刪除)

BEGIN Transaction t1 
DELETE FROM CacheItems WHERE ProfileGuid = 'B35DBBA4-54FC-4DF7-B1C8-E559D81DFEE3' 
DELETE FROM CacheFolders WHERE ProfileGuid = 'B35DBBA4-54FC-4DF7-B1C8-E559D81DFEE3' 
DELETE FROM CacheLists WHERE ProfileGuid = 'B35DBBA4-54FC-4DF7-B1C8-E559D81DFEE3' 
DELETE FROM CacheWebs WHERE ProfileGuid = 'B35DBBA4-54FC-4DF7-B1C8-E559D81DFEE3' 
+0

您可以使用TSQL_Locks模板運行SQL Server跟蹤併發布死鎖圖嗎?這將顯示死鎖的確切細節 – Vanlightly

+0

我試過了,它沒有寫入任何事件到死鎖事件文件。可能是因爲沒有死鎖? (之前從未使用該圖)。只要我進行一筆交易,另一筆交易順利進行。但是由於一項交易可能需要長達一個小時的時間,因此等待不是一種選擇。 – lolsharp

+0

您會看到一系列事件,如鎖定:死鎖鏈,死鎖圖。 – Vanlightly

回答

0

SQL Server可以鎖定不同級別取決於每個特定的查詢。這可以解釋爲什麼改變順序可以使一個transcation鎖定另一個。

,避免鎖的方式是

這些解決方案的兩個是危險的,因爲較低的隔離級別可能會導致所有類型的錯誤。

0

關鍵是要在事務之間完全隔離。也就是說,兩筆交易不需要觸及相同的記錄。

將記錄劃分爲並行組時,共享ID的記錄應位於同一組中。一個簡單的Parallel.Foreach是不夠的。每個組內的數據可以順序處理,而不用與另一個並行組共享任何數據。

除了應用程序中的這種邏輯隔離,您還需要確保不同的查詢在索引節點級別彼此隔離。確保所有查詢都使用索引查找,而不是掃描。這將避免兩個查詢在搜索記錄時將S鎖(共享鎖)放在同一記錄上,然後在嘗試刪除時無法將其轉換爲X鎖。使用「顯示實際執行計劃」運行每個查詢,並確保沒有看到索引掃描。如果你看到一個掃描,並不明白爲什麼然後發表評論。

+0

謝謝,索引掃描似乎是問題所在。其中一個查詢使用索引掃描或索引查找,具體取決於我要刪除的配置文件。我添加了執行計劃,也許你可以看看它並給我一個建議。 – lolsharp