dbt 中 unique key 的機制
淺談 dbt 在 RedShift 上 unique key 的運行機制
前些日子在跑 dbt 的時候遇到了幾張表格資料數量跟預期不同的地方,後來發現都跟 unique_key
有關係。
其實人家文件寫得算很清楚了,就怪當初自己沒仔細讀:
A
unique_key
enables updating existing rows instead of just appending new rows. If new information arrives for an existingunique_key
, that new information can replace the current information instead of being appended to the table. If a duplicate row arrives, it can be ignored.
欸,資料少了
這是最初的蠢問題,某張表格在設計的時候沒有仔細思考,後來被回報資料有缺漏。
而原因即是具有 unique_key
的 incremental table 在新增資料的過程會執行一個長得有點像 upsert) 的操作,因而導致舊資料列不見。
欸,資料多了
這是過了一段時間之後發生的問題——在認知到 unique_key
會有更新既有資料列的行為之後。
但這次的問題是資料多了,在某次跑 full refresh 後測試結果報錯,追了老半天才注意到 unique key 不能保證唯一——而其發生的條件還會跟使用的資料庫有關。
在 incremental_strategy 段落中有說到 Snowflake 跟 BigQuery 會採用 MERGE
來跑 unique key;在一次的資料轉換中若發生有多筆資料在 unique key 欄位上具有相同的值,則分別會有其對應的機制,以 BigQuery 而言它會自動以較晚抵達的資料覆蓋,即具有跟 upsert 極為相似特性。
但當然不是永遠這麼好康,我操作的環境是 RedShift,其底層是 PostreSQL,在這個世界裡我們沒有 MERGE
語法。追到了原始碼後注意到只有 delete+insert
可用,而其操作就是把目標表格中所有值有碰撞到的列刪除後、再將抽出的資料全部放入目標表格中。
故在 RedShift / PostreSQL 下,在同一次執行中有多個列在 unique key 欄位上具有同樣的值時,這些列就都會被放入表格中:
但這如果未來又有新的列來了,這些「多出來」的列又都會被刪掉:
不過這個操作也已經是 RedShift 官方推薦的手段了。