Community程式設計與開發github.com

ZrobDev/lakehouse

在選擇或處理湖倉儲存時使用 - Postgres vs 倉庫 vs 湖倉、Delta vs Iceberg vs DuckLake、小型 parquet 檔案造成的慢查詢、分區、OPTIMIZE/VACUUM/expire_snapshots、MERGE 或 schema-evolution 錯誤、目錄選擇、PySpark collect()/UDF/shuffle/skew,或使用 DuckDB 或 polars 在本機測試資料表。

lakehouse 是什麼?

此技能為開發人員和 AI 代理提供在開放資料表格式(如 Apache Iceberg、Delta Lake 和 DuckLake)中制定架構決策的全面指引。它涵蓋完整的決策樹:首先評估湖倉是否比更簡單的方案(如 Postgres 或雲端倉庫)更適用,然後根據主要引擎和目錄選擇正確的資料表格式,並針對 Parquet 檔案設計最佳配置(目標大小為 256 MB 至 512 MB,依查詢篩選條件進行分區)。此外,它還詳細說明自動化維護工作(如壓縮、快照過期和 VACUUM)、透過謂詞下推最佳化 MERGE 操作、使用 schema evolution 和時間旅行,並針對 PySpark 4.x 提供關鍵效能建議(包括使用 explain()、避免 collect() 以及適當使用廣播變數)。最後,它鼓勵在 DuckDB 或 polars 等工具中進行本機優先開發與測試,以在佈署到叢集之前驗證邏輯。整體而言,此技能旨在回答關於湖倉技術的常見陷阱,提供經過驗證的建議,並強調效能與成本效益,而非追逐最新的功能。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ZrobDev/data-engineering-skills/tree/HEAD/skills/lakehouse

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

lakehouse 是做什麼的?

針對開放資料表格式儲存和 Spark 程式碼提供參考級決策支援。版本和日期請參考 references/landscape-2026-11.md;在做出任何與版本相關的聲明之前,請先檢查該文件。如需 Databricks、Snowflake 或 AWS 服務的具體資訊,請使用 de-vendors 技能及其指向的官方廠商技能。

1. 是否適合使用湖倉?

從最便宜且符合需求的方案開始,僅在當所列出的觸發條件真實存在且可衡量時,才向上移動。

  • Postgres(或單一檔案集上的 DuckDB):當資料量低於約 1 TB、僅由一個引擎讀取,且同時進行的分析使用者很少時使用。原因:無需目錄、無需壓縮、無需執行叢集。
  • 雲端倉庫:當許多 SQL 使用者需要彈性的並行處理能力,且無人需要對相同資料使用第二個引擎時使用。原因:管理儲存、維護和管理成本已包含在價格中。
  • 湖倉:當至少符合以下一項條件時使用:數十 TB 或更多資料;多個引擎(Spark、Trino、DuckDB、Python)必須讀取同一份資料副本;機器學習或基於檔案的工作負載與 SQL 共享資料表;在您的資料量下,物件儲存的儲存成本明顯低於倉庫儲存;開放格式是硬性要求(用於退出、審計、廠商中立)。
  • 不要因為一個沒有具體數字的「未來規模」而選擇湖倉。在推薦之前,請詢問資料列數、每日成長量、同時線上的讀取者和引擎數量。
  • 對於仍希望使用開放格式的小型和中型資料:使用 DuckLake 或純 Parquet 搭配 DuckDB,勝過執行 Spark。

2. Parquet 配置

  • 每個檔案的目標大小為 128 MB 到 1 GB;如果不確定,目標設為 256 MB 到 512 MB。許多檔案小於 32 MB 會導致清單列出和開啟的成本主導查詢。
  • 每個檔案中的列群組大小約為 128 MB(未壓縮)(100 萬行以上);較小的群組會削弱最小/最大值修剪和壓縮效果。
  • 僅根據查詢會進行篩選的低基數欄位(日期或月份、區域)進行分區。一個好的分區應包含每個寫入批次至少一個目標大小的完整檔案;如果分區平均小於 1 GB,請改用更粗略的粒度或使用叢集。
  • 永遠不要根據高基數 ID 進行分區。對這類欄位使用叢集(Delta liquid clustering、Iceberg sort order / Z-order)。
  • 根據最常被篩選的欄位對檔案進行排序或叢集,以便最小值/最大值統計資訊能修剪列群組。
  • 串流或頻繁的微批次寫入會產生小型檔案;請安排壓縮作業,不要依賴寫入器來調整檔案大小。

3. 選擇資料表格式

根據您已有的引擎和目錄來決定,而不是根據功能清單。

  • Delta Lake:當 Databricks 或 Spark 是主要引擎,或 Unity Catalog 已經是治理層時選擇。與 Spark 的整合最強;其他引擎可以讀取,但寫入支援各異。
  • Apache Iceberg:當多個引擎必須寫入,或者您想要與廠商無關的目錄(REST)時選擇。v3 增加了刪除向量、列血緣和變體類型;在升級資料表之前,請確認路徑上的每個引擎和目錄都支援您要使用的 v3 功能,因為舊的讀取器在較新的格式版本上會失敗。
  • DuckLake:針對小型和中型資料、單一團隊,以及您已作為目錄操作的 SQL 資料庫(元資料存在於純文字資料表中)時選擇。執行成本低,生態系年輕;當 Spark、Trino 或 Snowflake 必須寫入相同資料表時,請不要選擇它。
  • 互通性層(Delta UniForm、用於 Delta 資料表的 Iceberg 中繼資料)是讀取路徑。每個資料表選擇一種格式作為記錄寫入器。
  • 之後更改格式需要重寫或進行元資料轉換;請謹慎選擇記錄寫入器。

4. 目錄

  • 目錄是提交協調器和存取控制點;在格式細節變得重要之前先選擇它。
  • Unity Catalog:以 Databricks 為中心的預設選項;為 Delta 和 Iceberg 提供治理。
  • AWS Glue 和 S3 Tables:當技術堆疊是 AWS 原生時選擇;S3 Tables 會為您管理壓縮,但會將您綁定在 AWS 上。
  • Iceberg REST 目錄(例如 Polaris):為了多引擎、多雲端中立性而選擇。
  • DuckLake:目錄是一個 SQL 資料庫;使用 Postgres 作為後端以支援多使用者使用,SQLite 或 DuckDB 僅適用於單一寫入器。
  • 永遠不要讓兩個目錄註冊相同的資料表路徑;對其中一個目錄的提交會破壞另一個目錄的檢視。

5. 維護(安排它,否則資料表會退化)

  • 壓縮小型檔案:Delta 的 OPTIMIZE、Iceberg 的 rewrite_data_files、DuckLake 的合併相鄰檔案。在大量資料攝入後執行,而不是每次寫入都執行。
  • 移除舊資料:Delta 的 VACUUM、Iceberg 的 expire_snapshots 加上孤立檔案清理、DuckLake 的快照過期後清理。保留時間必須超過您最長的讀取者或時間旅行視窗,因為在執行中的讀取器下刪除檔案會導致其出錯。
  • 叢集或 Z-order 僅針對出現在篩選條件中的欄位進行;重新叢集會重寫資料並消耗計算資源。
  • 在之前和之後檢查檔案數量和平均檔案大小;如果維護作業沒有改變任何一個,則代表它沒有做任何事。
  • 如果引擎提供,請先試用乾燥模式的 VACUUM 或孤立檔案移除。

6. MERGE、Schema 演進、時間旅行

  • MERGE:先在比對鍵上對來源進行去重(重複的來源比對會失敗或導致雙重套用)。在 ON 子句中包含一個分區或叢集謂詞,以便引擎修剪檔案而不是掃描整個資料表。
  • 在大型資料表上,優先使用附加(append)加上定期 MERGE,或使用冪等鍵,而不是重複執行全表 MERGE。
  • Schema 演進:新增欄位是安全的;重新命名和型別擴展取決於格式和版本(Delta 中的欄位對應,Iceberg 中的欄位 ID)。在重新命名之前,請檢查相關讀取器是否支援。永遠不要在不受控的生產管線輸入上啟用自動 schema 合併。
  • 時間旅行是除錯、稽核和回滾的工具,而不是備份。它會消耗保留的檔案;保留時間越長,儲存空間越多,元資料也越慢。請謹慎設定保留時間,並為關鍵資料表保留真實的備份。

7. PySpark 4.x 要點

  • 轉換是懶執行的;在採取行動之前什麼都不會執行。建立一個計畫,觸發一次寫入;重複的 count() 或 show() 會重新執行整個計畫,除非您刻意使用了快取。
  • 避免對大型資料使用 collect()、toPandas() 和 .rdd;它們會將所有資料拉取到驅動程式。請先進行限制或彙總。
  • 使用內建函數或 SQL 表達式,而不是 Python UDF。UDF 會阻礙最佳化器的下推並序列化資料列。如果無法避免,請使用向量化(Arrow)UDF。
  • 寬操作(join、groupBy、window、distinct)會進行混洗。在它們之前進行過濾和投影;使用 explain() 檢查計畫。
  • 當一個小型關聯表可以放入執行器記憶體時,廣播它(broadcast(df));不要廣播一個無界的資料表。
  • Adaptive Query Execution 在 Spark 4.x 中預設開啟,並處理分區合併、傾斜連接和連接策略切換;在閱讀計畫後進行調整,而不是之前。
  • 傾斜表現為一個緩慢的任務;只有在 AQE 證明不足之後,才對熱鍵進行加鹽或隔離處理。
  • Spark Connect 是客戶端-伺服器模式:程式碼作為輕量級客戶端通過遠端工作階段執行。不要在 Connect 程式碼中依賴驅動程式本地的 JVM 內部(sparkContext、RDD API)。
  • 透過壓縮來指定明確的目標檔案大小進行寫入,而不是重新分區到一個猜測的數字。

8. 本機優先路徑

在將程式碼部署到叢集之前,使用 DuckDB 或 polars 進行開發和測試。

  • DuckDB 透過擴充功能讀取 Delta 和 Iceberg,並附加 DuckLake 目錄;polars 使用謂詞下推方式惰性讀取 Delta 和 Iceberg。
  • 使用樣本或一個分區對照實際的資料表配置進行測試,以便檔案修剪行為相符。
  • 在實際引擎上確認寫入語意(MERGE、刪除向量、v3 功能);本機讀取器可能落後於格式功能。將成功的本機讀取視為必要條件,而非充分條件。

程序

  1. 取得數字:大小、成長量、寫入器、讀取器、引擎。 2. 逐步檢查第 1 節;停在最便宜且符合需求的方案。 3. 如果是湖倉:選擇目錄,然後選擇格式(第 4 節、第 3 節)。 4. 在首次載入之前設定配置和維護計畫。 5. 在本機建立原型(第 8 節),然後在叢集上執行並審查 explain() 的輸出。 6. 使用檔案計數和查詢計畫進行驗證,而不是憑假設。

已知陷阱和修正:請參閱 references/gotchas.md。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相關技能