題幹與適用場景
團隊用 DuckDB 讀取 Parquet 變更檔案,想在本地分析庫維護客戶維表與歷史價格。請說明何時使用 MERGE INTO,如何處理同一鍵多行、刪除、SCD Type 2、重跑與失敗恢復。
面試官考察點
考察你是否理解匹配條件、動作順序、來源唯一性與交易邊界;能否把 SQL 便利性轉成可重跑的資料管道,並設計品質、稽核與回滾。
回答前需要釐清的問題
先問業務主鍵、事件時間與去重規則,是否需要保留歷史版本;再確認來源是否可能重複、遲到或含刪除,以及失敗後能否重建目標表。不要把 MERGE 自動視為 CDC exactly-once。
30 秒回答
「我會先在 staging 依業務鍵與事件時間去重,驗證每個目標鍵最多一筆可套用變更,再在交易中執行 MERGE。目前值表用匹配更新與未匹配插入,歷史表用 SCD Type 2 關閉舊版本並插入新版本;刪除與重跑也要有明確語意。每批記錄輸入快照、筆數與校驗結果,失敗就回滾並用同一快照重試。」
分步驟深入解答
定義目標表語意
區分目前快照表與歷史表。目前表追求最新狀態;SCD Type 2 需要 validfrom、validto、is_current 與版本約束。
先建立可稽核 staging
保留來源檔名、批次 ID、讀取時間與列雜湊。依業務鍵、事件時間與來源優先級去重,拒絕無法決定勝負的並列資料。
設計匹配與動作
匹配條件只使用穩定業務鍵,不把可變屬性放進 ON。明確 WHEN MATCHED 更新、WHEN NOT MATCHED 插入和 WHEN NOT MATCHED BY SOURCE 刪除策略,避免誤刪遲到資料。
處理 SCD Type 2
對變化的 current 列先設定結束時間,再插入新版本;相同內容不產生新版本。用唯一約束或品質查詢保證同一鍵只有一個 current 版本。
保證重跑與交易
批次 ID 和輸入快照讓任務可重跑。MERGE 與稽核寫入應在同一交易;失敗不提交部分結果,重試使用相同 staging,而非重新讀取可能變化的檔案。
監控與回滾
比較來源/目標插入、更新、刪除筆數,檢查孤兒鍵、重複 current 列與時間逆序。保留變更前快照或可重建路徑,異常時按批次回滾。
高品質示範回答
我會把 Parquet 檔案先落入帶批次中繼資料的 staging,依業務鍵與事件時間去重並做筆數、空值和刪除比例校驗。目前表用穩定鍵匹配更新/插入;歷史表對變化列關閉舊版本並插入新版本,保證一個鍵只有一個 current。MERGE、稽核與批次狀態放在同一交易,失敗用同一快照重跑。監控每批差異計數與重複版本,異常按批次回滾或重建。
常見錯誤
直接對原始檔案 MERGE
來源重複會讓結果不確定或重複更新;應先 staging、去重和品質門禁。
把可變欄位放入匹配條件
客戶改名後會被當成新鍵;匹配應使用穩定業務鍵。
SCD Type 2 只做 INSERT
舊版本不會關閉,查詢會得到多個 current;必須維護有效期和唯一約束。
重跑時重新讀取來源
檔案可能已替換或新增,導致不同結果;應凍結輸入快照和批次 ID。
追問及應對
同一鍵在來源出現兩筆不同事件怎麼辦?
按明確的事件時間、版本或來源優先級選一筆;無法判定就隔離到 quarantine,不靜默覆寫。
如何處理遲到刪除?
依刪除事件時間與目標版本判斷是否生效,記錄 tombstone,並防止舊刪除覆蓋更新資料。
MERGE 失敗後如何確認沒有部分提交?
把 MERGE、稽核與批次狀態放在交易中,失敗檢查目標筆數與批次狀態,再用同一 staging 重試。
什麼時候不用 MERGE?
若批次接近全量替換、匹配邏輯複雜或需要跨系統交易,可先生成新表再原子切換,降低逐列動作的不確定性。