在高併發 OLTP 系統中,**大交易** 是阻塞風暴的核心推手。本文透過實戰案例,展示大交易如何從「保護資料一致性」演變為「系統癱瘓元兇」,並提供漸進式解決方案:快取緩衝 → 拆解交易 → 公私資料分離 → 最終一致性模式。
-- 交易 1: 業務核心大交易 (低頻但耗時)
BEGIN TRAN
INSERT INTO Message (Id, Col1, Col2...) VALUES (@Id, @Col1, @Col2...); -- 私有資料
UPDATE Thread SET Post_Count = NVL(Post_Count,0) + 1 WHERE Id = @V_Id; -- 公開熱點資料
UPDATE Test_User SET Sum_Reply = Sum_Reply + 1 WHERE UserId = @V_UserId; -- 私有資料
COMMIT TRAN
-- 交易 2: 高頻熱點更新 (極高頻)
UPDATE Thread SET View_Count = NVL(View_Count,0) + 1 WHERE Id = @V_Id;
LCK_M_X 等待激增、回應時間飆升分析交易 1 三條語句的資料特性:
| 語句 | 資料屬性 | 阻塞風險 | 歸類 |
|---|---|---|---|
| INSERT Message | 新增單筆,無衝突 | 無 | 私有 |
| UPDATE Thread.Post_Count | 熱點列,高併發更新 | 極高 | 公開 |
| UPDATE Test_User.Sum_Reply | 按 UserId 更新,用戶隔離 | 低 | 私有 |
重構方案:
-- 交易 1_1: 公開熱點資料獨立交易 (極短、極快)
BEGIN TRAN
UPDATE Thread SET Post_Count = NVL(Post_Count,0) + 1 WHERE Id = @V_Id;
COMMIT TRAN
-- 交易 1_2: 私有資料合併交易 (較長但無衝突)
BEGIN TRAN
INSERT INTO Message (Id, Col1, Col2...) VALUES (@Id, @Col1, @Col2...);
UPDATE Test_User SET Sum_Reply = Sum_Reply + 1 WHERE UserId = @V_UserId;
COMMIT TRAN
| 指標 | 原大交易 | 拆解後 | 改善 |
|---|---|---|---|
| Thread 表鎖持有時間 | ~50-200ms (含 INSERT/UPDATE User) | ~1-5ms (僅 UPDATE Thread) | 95%+ 降低 |
| 交易 1 自我阻塞概率 | 高 | 極低 | 消除熱點競爭 |
| 資料一致性風險 | 強一致 (ACID) | 最終一致 (Message/User 可能比 Thread 晚可見) | 業務可接受 (計數器延遲秒級) |
| 應用複雜度 | 低 | 中 (需處理兩階段提交邏輯) | 可控 |
若業務**嚴格要求強一致** (如金融帳務),可採用:
Version 欄位,UPDATE ... SET Count=Count+1, Version=Version+1 WHERE Id=@Id AND Version=@OldVer,失敗則重讀重試大交易不是洪水猛獸,**關鍵在於識別其內部的衝突域並加以隔離**。將這套分析框架納入架構評審清單,讓 OLTP 系統在高併發下穩健演進。