🔍解密「系統鎖死」:用日常語言看懂軟體工程師如何解決資料庫死結問題

 

🔍 前言:看似神秘的「鎖死」到底是什麼?

想像一下,你和朋友一起在冰箱裡拿飲料。你拉著冰箱門不放,朋友又同時拉著同一扇門。結果?誰也打不開,大家都卡住。
這種情況在資料庫裡也會發生,專業名稱叫做 「死結(Deadlock)」

這次的案例發生在一個自動處理晶圓資料(wafer data)的系統裡。系統同時開了多個背景任務,一邊在刪資料、一邊在更新資料。結果不同的任務互相「鎖住」了資料庫資源,造成 SQL Server 無法繼續執行。


🧠 為什麼會發生死結?

死結不是 bug,而是資料庫「太忙」的副作用。
簡單來說,當:

  • 任務 A 鎖住了表 A,準備要動表 B

  • 任務 B 鎖住了表 B,準備要動表 A

兩個任務互相等待,資料庫就陷入「我等你、你等我」的無限循環。
SQL Server 為了救場,會強制中止其中一個任務,留下錯誤訊息:

「交易在鎖定資源上被另一個處理序鎖死,已被選為犧牲者。」



⚙️ 軟體工程師怎麼解決?

這類問題聽起來複雜,其實解法可以用生活邏輯來理解。

1️⃣ 讓資料庫「找得到路」

在刪除資料時,如果資料庫沒有地圖(索引),它會整張表掃描,鎖住很多筆資料。
工程師會幫它加上「快速搜尋索引」,像是:

  • 幫每筆資料加上標籤(例如「物件編號」)

  • 讓刪除只影響該筆資料,不會把整張表鎖起來

👉 結果:刪除變快,鎖衝突變少。


2️⃣ 固定「刪除順序」

想像你和朋友要清冰箱:一個先清上層、另一個先清下層。
如果大家都用不同順序,就容易互卡。
同樣的,系統也要統一先刪表 A 再刪表 B,避免交叉鎖。


3️⃣ 加上「重試機制」

死結常常是「暫時的衝突」。
工程師會加上簡單的自動重試邏輯:
若第一次失敗,等個一秒再試一次,通常第二次就成功。

這樣就像遊樂園入口排隊,第一輪人太多就稍等再進。


4️⃣ 減少同時開太多執行緒

如果同時開十個任務都在刪資料,衝突機率自然變高。
將同時處理數降到兩三個,可以顯著減少問題。
(有點像餐廳廚師太多也會互相撞鍋)


5️⃣ 啟用「快照讀取模式」

資料庫有個設定叫 Read Committed Snapshot
開啟後,資料庫會「拍一張快照」給讀取端,讓讀取和刪除互不干擾。
這招非常適合同時有多任務運作的系統。


🚀 結果:系統重新穩定,效能更好

經過上述優化後,系統重新跑起來:

  • 每批資料處理時間從 3 分鐘降到 1 分半

  • 不再出現「鎖死犧牲者」的錯誤

  • 所有檔案能穩定進入資料庫

使用者不再看到失敗通知,整個流程自動、穩定又快速。


🏁 結語

死結看似可怕,其實是系統在「自我保護」。
只要了解它發生的原因,並透過索引、順序、重試與限制併發,就能輕鬆避免。

用一句話總結:

「死結不是錯,而是系統在提醒你該排隊了。」

留言

這個網誌中的熱門文章

🔍Vue.js 專案錯誤排查:解決 numericFields is not defined 與合併儲存格邏輯最佳化

🔎EF Core 連 Oracle 出現 ORA-00600 [kpp_concatq:2] 的完整排錯指南(含 EF Core ToString/CultureInfo 錯誤)

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題