最佳做法:Delta Lake

本文說明使用 Delta Lake 時的最佳做法。

Databricks 建議使用預測性優化。 請參閱 Delta Lake 的預測優化。

在相同位置刪除和重新建立資料表時,您應該一律使用 CREATE OR REPLACE TABLE 語句。 請參閱 卸除或取代 Delta 數據表

使用液體叢集進行優化的數據略過

Databricks 建議使用液體叢集,而不是數據分割、Z 順序或其他數據組織策略,以優化數據配置以略過數據。 請參閱針對差異資料表使用液態叢集 \(英文\)。

壓縮檔案

預測優化會自動在 Unity 目錄受控數據表上執行 OPTIMIZEVACUUM 命令。 請參閱 Delta Lake 的預測優化。

Databricks 建議經常執行 OPTIMIZE 命令來壓縮小型檔案。

注意

此作業不會移除舊檔案。 若要移除它們,請 執行 VACUUM 命令。

取代數據表的內容或架構

有時候您可能會想要取代 Delta 資料表。 例如:

  • 您發現數據表中的數據不正確,而且想要取代內容。
  • 您想要重寫整個數據表,以執行不相容的架構變更(例如變更數據行類型)。

雖然您可以刪除 Delta 資料表的整個目錄,並在相同的路徑上建立新的資料表,但不建議這麼做,因為:

  • 刪除目錄沒有效率。 包含非常大型檔案的目錄可能需要數小時甚至數天才能刪除。
  • 您會遺失已刪除檔案中的所有內容;如果您刪除錯誤的數據表,則很難復原。
  • 目錄刪除不是不可部分完成的。 當您刪除資料表時,讀取資料表的並行查詢可能會失敗或看到部分數據表。

如果您不需要變更資料表架構,您可以從 Delta 資料表刪除 資料並插入新的資料,或 更新 資料表以修正不正確的值。

如果您想要變更數據表架構,可以不可部分完成地取代整個數據表。 例如:

Python

dataframe.write \
  .format("delta") \
  .mode("overwrite") \
  .option("overwriteSchema", "true") \
  .saveAsTable("<your-table>") # Managed table

dataframe.write \
  .format("delta") \
  .mode("overwrite") \
  .option("overwriteSchema", "true") \
  .option("path", "<your-table-path>") \
  .saveAsTable("<your-table>") # External table

SQL

REPLACE TABLE <your-table> USING DELTA AS SELECT ... -- Managed table
REPLACE TABLE <your-table> USING DELTA LOCATION "<your-table-path>" AS SELECT ... -- External table

Scala

dataframe.write
  .format("delta")
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable("<your-table>") // Managed table

dataframe.write
  .format("delta")
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .option("path", "<your-table-path>")
  .saveAsTable("<your-table>") // External table

此方法有多個優點:

  • 覆寫數據表的速度會更快,因為它不需要以遞歸方式列出目錄或刪除任何檔案。
  • 舊版的數據表仍然存在。 如果您刪除錯誤的數據表,您可以輕鬆地使用時間移動來擷取舊數據。 請參閱使用 Delta Lake 資料表歷程記錄
  • 這是不可部分完成的作業。 當您刪除資料表時,並行查詢仍然可以讀取數據表。
  • 由於 Delta Lake ACID 交易保證,如果覆寫數據表失敗,數據表會處於先前的狀態。

此外,如果您想要刪除舊檔案,以在覆寫數據表之後節省儲存成本,您可以使用 VACUUM 來刪除它們。 它已針對檔案刪除進行優化,通常比刪除整個目錄更快。

Spark 快取

Databricks 不建議基於下列原因使用 Spark 快取:

  • 您會遺失任何略過的數據,這些數據可能來自在快 DataFrame取 中新增的其他篩選。
  • 如果數據表是使用不同的標識碼存取,則快取的數據可能不會更新。

Apache Spark 上 Delta Lake 與 Parquet 之間的差異

Delta Lake 會自動處理下列作業。 您絕對不應該手動執行這些作業:

  • REFRESH TABLE:差異數據表一律會傳回最新的資訊,因此不需要在變更之後手動呼叫 REFRESH TABLE
  • 新增和移除數據分割:Delta Lake 會自動追蹤數據表中存在的數據分割集,並在新增或移除資料時更新清單。 因此,不需要執行 ALTER TABLE [ADD|DROP] PARTITIONMSCK
  • 載入單一分割區:不需要直接讀取分割區。 例如,您不需要執行 spark.read.format("parquet").load("/data/date=2017-01-01")。 請改用 WHERE 子句來略過資料,例如 spark.read.table("<table-name>").where("date = '2017-01-01'")
  • 請勿手動修改數據檔:D elta Lake 會使用事務歷史記錄,以不可部分完成的方式認可數據表的變更。 請勿直接修改、新增或刪除 Delta 資料表中的 Parquet 資料文件,因為這可能會導致數據或數據表損毀。

改善 Delta Lake 合併的效能

您可以使用下列方法來減少合併所需的時間:

  • 減少相符專案的搜尋空間:根據預設,作業會 merge 搜尋整個 Delta 數據表,以在源數據表中尋找相符專案。 加快 merge 速度的其中一個方法是在比對條件中新增已知的條件約束來減少搜尋空間。 例如,假設您有一個由 和 date 分割country的數據表,而且您想要用來merge更新最後一天和特定國家/地區的資訊。 新增下列條件可讓查詢更快,因為它只會在相關的分割區中尋找相符專案:

    events.date = current_date() AND events.country = 'USA'
    

    此外,此查詢也會減少與其他並行作業衝突的機會。 如需詳細資訊,請參閱 Azure Databricks 上的隔離等級和寫入衝突。

  • 壓縮檔案:如果數據儲存在許多小型檔案中,讀取要搜尋相符項目的數據可能會變慢。 您可以將小型檔案壓縮成較大的檔案,以改善讀取輸送量。 如需詳細資訊,請參閱 在 Delta Lake 上使用優化來壓縮數據檔。

  • 控制隨機分割區以進行寫入:作業 merge 會多次隨機顯示數據,以計算和寫入更新的數據。 用來隨機顯示的工作數目是由Spark會話組態 spark.sql.shuffle.partitions所控制。 設定此參數不僅會控制平行處理原則,也會決定輸出檔案的數目。 增加值會增加平行處理原則,但也會產生較多較小的數據檔。

  • 啟用優化的寫入:針對數據分割數據表, merge 可以產生比隨機分割區數目更大的小型檔案。 這是因為每個隨機工作都可以在多個分割區中寫入多個檔案,而且可能會成為效能瓶頸。 您可以啟用優化的寫入來減少檔案數目。 請參閱 Azure Databricks 上 Delta Lake 的優化寫入。

  • 調整數據表中的檔案大小:Azure Databricks 可以自動偵測 Delta 數據表是否有經常 merge 重寫檔案的作業,而且可能會選擇減少重寫檔案的大小,以預期未來會進一步重寫檔案。 如需詳細資訊,請參閱微調檔案大小一節

  • 低隨機合併:低隨機合併提供優化實MERGE作,為最常見的工作負載提供更好的效能。 此外,它會保留現有的數據配置優化,例如 未修改數據上的 Z 順序

管理數據重新存取

在每個查詢開始時,Delta 數據表會自動更新為最新版的數據表。 當命令狀態報告時,可以在筆記本中觀察到此程式: Updating the Delta table's state。 不過,在數據表上執行歷程記錄分析時,您不一定需要最新的最後一分鐘數據,特別是針對經常內嵌串流數據的數據表。 在這些情況下,您可以在 Delta 數據表的過時快照集上執行查詢。 這種方法可以降低從查詢取得結果的延遲。

您可以設定過時數據的容錯,方法是使用 時間字串值設定 Spark 工作階段 spark.databricks.delta.stalenessLimit 設定,例如 1h15m (分別為 1 小時或 15 分鐘)。 此設定為會話特定,且不會影響其他存取數據表的用戶端。 如果數據表狀態已在過期限制內更新,則數據表的查詢會傳回結果,而不需要等待最新的數據表更新。 此設定絕不會防止數據表更新,而且當傳回過時的數據時,更新會在背景中處理。 如果最後一個數據表更新早於過時限制,查詢在數據表狀態更新完成之前不會傳回結果。

低延遲查詢的增強檢查點

Delta Lake 會以優化頻率將檢查點寫入 Delta 數據表的匯總狀態。 這些檢查點可作為計算數據表最新狀態的起點。 如果沒有檢查點,Delta Lake 必須讀取代表認可事務歷史記錄的大型 JSON 檔案集合,以計算數據表的狀態。 此外,數據行層級統計數據 Delta Lake 用來執行 略過 的數據會儲存在檢查點中。

重要

Delta Lake 檢查點與 結構化串流檢查點不同。

數據行層級統計數據會儲存為結構與 JSON(為了回溯相容性)。 結構格式可讓 Delta Lake 讀取更快,因為:

  • Delta Lake 不會執行昂貴的 JSON 剖析來取得數據行層級統計數據。
  • Parquet 資料行剪除功能可大幅減少讀取數據行統計數據所需的 I/O。

結構格式可讓優化集合,將 Delta Lake 讀取作業的額外負荷從秒減少到數十毫秒,這可大幅降低短查詢的延遲。

管理檢查點中的數據行層級統計數據

您可以使用資料表屬性 delta.checkpoint.writeStatsAsJsondelta.checkpoint.writeStatsAsStruct來管理以檢查點撰寫統計數據的方式。 如果這兩個數據表屬性都是 false,Delta Lake 就無法 執行略過的數據。

  • Batch 會以 JSON 和結構格式寫入寫入統計數據。 delta.checkpoint.writeStatsAsJsontrue
  • delta.checkpoint.writeStatsAsStruct 預設為未定義。
  • 讀取器會在可用時使用結構數據行,否則會回復為使用 JSON 資料行。

重要

增強的檢查點不會中斷與 開放原始碼 Delta Lake 讀取器的相容性。 不過,將 設定 delta.checkpoint.writeStatsAsJsonfalse 可能會影響專屬 Delta Lake 讀取器。 請連絡您的廠商以深入瞭解效能影響。

啟用結構化串流查詢的增強檢查點

如果您的結構化串流工作負載沒有低延遲需求(低於延遲),您可以執行下列 SQL 命令來啟用增強的檢查點:

ALTER TABLE [<table-name>|delta.`<path-to-table>`] SET TBLPROPERTIES
('delta.checkpoint.writeStatsAsStruct' = 'true')

您也可以藉由設定下表屬性來改善檢查點寫入延遲:

ALTER TABLE [<table-name>|delta.`<path-to-table>`] SET TBLPROPERTIES
(
 'delta.checkpoint.writeStatsAsStruct' = 'true',
 'delta.checkpoint.writeStatsAsJson' = 'false'
)

如果您的應用程式中略過數據並無用處,您可以將這兩個屬性設定為 false。 然後不會收集或寫入任何統計數據。 Databricks 不建議使用此設定。