處理同一張表的數據時加鎖、死鎖的解決方法
我的數據庫有一個表:tableX。
Task1將密集的 INSERT(每分鐘 1000 條記錄)作為要處理的記錄,很少將 UPDATE(每分鐘 1-2 條記錄)作為要重新計算的記錄。
同時其他Task2選擇未處理的記錄(由 Task1 插入),然後在****一個事務中將新記錄(已處理)插入到同一個 tableX 中(計算時間太長,最多 10 秒)。
Task3重新計算 UPDATED 記錄(通過 Task1):只是 UPDATEs tableX。
有人可以推薦設計以避免這種情況下的長時間鎖定和死鎖。在插入時按順序處理所有 INSERTED 記錄非常重要!
1)我應該分開(創建一個新的tableX2)已處理和未處理的記錄嗎?
2)我應該在 Task1 中分離事務並在兩個分離的事務中執行 SELECT 和 INSERT 嗎?
3)我應該使用 rowlock、readpast…hints 以及在哪裡(它可以幫助我)嗎?
簡單的這個。
Task1 不應該插入到主表中,而是一個臨時表,比如 tableXstaging。此表應包含標識列或 row_processed(TINYINT 或 BIT)列。
Task1 一直插入到 tableXstaging 中。我會允許更新直接更新主表,因為它們很少見。
每分鐘執行一次的另一個任務將:從 tableXstaging 設置 MaxID = max(identity column),或者如果您使用 row_processed,則設置 row_processed = 1。這為您提供了批處理。此任務將向 tableX 中插入身份 <= MaxID 的所有記錄,或者如果您使用 row_processed,則 WHERE row_processed = 1。單次插入主 tableX 非常快。然後從 tableXstaging 中刪除 row_processed = 1 或 WHERE identity<=MaxID。我會選擇身份,因為您不需要更新 row_processed = 1 where row_processed = 0,因此會更快。
tableX 現在每分鐘只插入一次。
實際上重新閱讀您的問題,我會選擇 row_processed,為您的第一批設置 row_processed = 1。
任務 2 在暫存表 WHERE row_processed = 1 上工作。然後設置 row_processed = 2。
任務 3 在暫存表 WHERE row_processed = 2 上工作。然後設置 row_processed = 3。
最後,SET XACT_ABORT ON;BEGIN TRAN,一鍵將記錄插入 tableX (row_processed=3)。這是非常有效的,因為臨時表很小,並且 tableX 將非常大而且很慢(相對於臨時表而言)。然後從 staging where row_processed = 3 中刪除。 COMMIT;