下午兩點,一支批次修正程式把不該納入的訂單也更新成「已取消」。兩點二十分,客服發現異常,但這段時間裡,系統仍持續接單,倉庫也完成了部分訂單的出貨。
正式環境有主備資料庫,兩台都正常運作,錯誤更新也已經同步。這時切換到備援資料庫,看到的仍是相同的錯誤狀態。
團隊有備份,也有時間點還原能力。不過,若直接把正式資料庫退回事故前,這二十分鐘內正常建立的訂單與合法修改也會一起消失。這次要做的,是找回受損的資料,同時保留仍然正確的變更。
先控制影響,再把歷史資料另外還原出來
首先需要停用造成錯誤的批次工作,保留執行紀錄,找出受影響的訂單與欄位。受影響範圍要依實際執行條件、紀錄與資料比對來確認,不能只查出目前所有「已取消」的訂單,因為其中也包含正常取消的資料。
對狀態有疑慮的訂單,可以暫時限制取消、出貨等依賴狀態的操作,未受影響的訂單則繼續服務。限制範圍也要包含背景工作,避免資料還原與比對的過程中,背景程式又繼續觸發後續處理。若還沒完全掌握範圍,就需要先擴大相關操作的限制,再依證據逐步縮小。
接著,把事故前的資料還原到另一個隔離環境。正式服務仍使用原本的資料庫,這份歷史資料只供查詢與比對,不接上正式排程,也不讓它發出任何通知或出貨要求。
這裡的「還原成功」,指的是另一份歷史資料庫已經建立完成,還沒有修改正式資料。時間點還原也不是任意挑一個時間就能完成;例如SQL Server需要適用的資料備份,以及涵蓋目標時間的連續交易紀錄備份。目標時間要落在錯誤更新之前,並核對還原結果,不能把發現異常的時間當成事故開始時間。
舊資料是線索,不一定是現在的答案
假設一張訂單在事故前是「待出貨」,被誤改成「已取消」後,倉庫仍依先前收到的工作單完成出貨。歷史資料可以證明它原本待出貨,卻不能證明現在還應該待出貨。
因此,必須結合操作紀錄、出貨紀錄與必要的外部查詢,判斷現在應有的狀態。若錯誤取消已觸發退款或庫存釋放,只改回訂單狀態也不會自動撤銷那些結果,還需要處理後續影響。證據不足的訂單則保留待確認,不能拿舊值當成現成的答案。
另一張訂單可能只是狀態被改錯,但客服後來合法修改了配送地址。修復時就應保留新地址,只處理確認有誤的欄位,不能把整筆歷史資料盲目覆蓋回去。若修復牽涉多張資料表,也要確保彼此的狀態保持一致。
AI可以協助比對資料、整理事件順序與產生修復腳本,但比對結果中的「不同」不等於「錯誤」。把事故範圍、後續操作與業務規則一起提供,才能判斷哪些差異需要修正;缺少的事實,也不會因為腳本寫得完整就自動補齊。
寫回去的那一刻,資料可能又變了
即使已經整理好修復清單,正式系統仍可能在過程中收到物流回報或其他更新。若先查詢、隔幾分鐘再直接寫回,比對時的結論可能已經不適用。
修復可以在同一次更新裡,檢查資料版本是否仍與核對時一致,再寫入確認過的值。條件不符就跳過並重新判斷,避免覆蓋掉後續發生的合法變更。只檢查狀態是否仍為「已取消」並不足夠,因為這段期間也可能發生一次真正的取消。
執行前先核對預計異動範圍,保留修復前後的值與判斷依據。資料量大時,可以分批執行並觀察鎖定、交易日誌與副本同步的影響,但分批不能拆散必須一起完成的關聯更新。
完成後除了核對筆數,也要確認訂單、出貨與其他相關紀錄是否一致,再解除受影響操作的限制。另一份資料庫還原完成,只是提供了修復依據;正式資料與後續流程都恢復正確,才算真正完成這次處理。
備份從來不等於一鍵還原。備份只是幫你找回過去的事實,真正的還原,是在保護現場正確變更的前提下,精準修復現在應有的狀態。
「資料庫還原成功,系統回到十分鐘前了!」
「那這十分鐘內,客戶已經付款的訂單呢?」
「訂單沒了,但錢還在。」
「我們是購物網站,不是募資平台。」
![]()