最佳做法:Delta Lake
本文描述使用 Delta Lake 時的最佳做法。
Databricks 建議使用預測性最佳化。 請參閱 Unity Catalog 受控資料表的預測性最佳化。
在相同位置刪除和重新建立資料表時,您應該一律使用 CREATE OR REPLACE TABLE
陳述式。 請參閱 卸除或取代 Delta 資料表。
拿掉舊版 Delta 設定
Databricks 建議在升級至新的 Databricks Runtime 版本時,從 Spark 設定和資料表屬性中移除最明確的舊版 Delta 設定。 舊版設定可防止 Databricks 導入的新最佳化和預設值套用至已移轉的工作負載。
使用液體叢集進行最佳化的資料略過
Databricks 建議使用液體叢集,而不是資料分割、Z 順序或其他資料組織策略,以最佳化資料結構描述以略過資料。 請參閱針對差異資料表使用液態叢集。
壓縮檔案
預測最佳化會自動在 Unity 目錄受控資料表上執行 OPTIMIZE
和 VACUUM
命令。 請參閱 Unity Catalog 受控資料表的預測性最佳化。
Databricks 建議經常執行 OPTIMIZE 命令來壓縮小型檔案。
注意
此作業不會移除舊檔案。 若要將其移除,請執行 VACUUM 命令。
取代資料表的內容或結構描述
有時候您可能會想要取代 Delta 資料表。 例如:
- 您發現資料表中的資料不正確,而且想要取代內容。
- 您想要重寫整個資料表,以執行不相容的結構描述變更(例如變更資料行類型)。
雖然您可以刪除 Delta 資料表的整個目錄,並在相同的路徑上建立新的資料表,但不建議這麼做,因為:
- 刪除目錄沒有效率。 包含非常大型檔案的目錄可能需要數小時甚至數天才能刪除。
- 您會遺失已刪除檔案中的所有內容;如果您刪除錯誤的資料表,則很難復原。
- 目錄刪除不是不可部分完成的。 當您刪除資料表時,讀取資料表的並行查詢可能會失敗或看到部分資料表。
如果您不需要變更資料表結構描述,您可以從 Delta 資料表刪除資料並插入新的資料,或更新資料表以修正不正確的值。
如果您想要變更資料表結構描述,可以不可部分完成地取代整個資料表。 例如:
Python
dataframe.write \
.mode("overwrite") \
.option("overwriteSchema", "true") \
.saveAsTable("<your-table>") # Managed table
dataframe.write \
.mode("overwrite") \
.option("overwriteSchema", "true") \
.option("path", "<your-table-path>") \
.saveAsTable("<your-table>") # External table
SQL
REPLACE TABLE <your-table> AS SELECT ... -- Managed table
REPLACE TABLE <your-table> LOCATION "<your-table-path>" AS SELECT ... -- External table
Scala
dataframe.write
.mode("overwrite")
.option("overwriteSchema", "true")
.saveAsTable("<your-table>") // Managed table
dataframe.write
.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] PARTITION
或MSCK
。 - 載入單一分割區:不需要直接讀取分割區。 例如,您不需要執行
spark.read.format("parquet").load("/data/date=2017-01-01")
。 請改用WHERE
子句來略過資料,例如spark.read.table("<table-name>").where("date = '2017-01-01'")
。 - 請勿手動修改資料檔:Delta Lake 會使用事務歷史記錄,以不可部分完成的方式認可資料表的變更。 請勿直接修改、新增或刪除 Delta 資料表中的 Parquet 資料文件,因為這可能會導致資料或資料表損毀。
改善 Delta Lake 合併的效能
您可以使用下列方法來減少合併所花費的時間:
減少相符項目的搜尋空間:根據預設,
merge
作業會搜尋整個 Delta 資料表,以在來源資料表中尋找相符項目。 加快merge
速度的其中一個方法是在比對條件中新增已知的條件約束來減少搜尋空間。 例如,假設您有一個由country
和date
分割的資料表,而且您想要使用merge
來更新最後一天和特定國家/地區的資訊。 新增下列條件可讓查詢更快,因為它只會在相關的分割區中尋找相符項目:events.date = current_date() AND events.country = 'USA'
此外,此查詢也會減少與其他並行作業衝突的機會。 如需詳細資料,請參閱 Azure Databricks 上的隔離等級和寫入衝突。
壓縮檔案:如果資料儲存在許多小型檔案中,讀取要搜尋相符項目的資料可能會變慢。 您可以將小型檔案壓縮成較大的檔案,以改善讀取輸送量。 請參閱最佳化資料檔結構描述。
控制隨機分割區以進行寫入:
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
設定,例如 1h
或 15m
(分別為 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.writeStatsAsJson
和 delta.checkpoint.writeStatsAsStruct
來管理以檢查點撰寫統計資料的方式。 如果這兩個資料表屬性都是 false
,Delta Lake 就無法執行資料略過。
- Batch 會以 JSON 和結構格式寫入寫入統計資料。
delta.checkpoint.writeStatsAsJson
為true
。 delta.checkpoint.writeStatsAsStruct
預設為未定義。- 讀取器會在可用時使用結構資料行,否則會回復為使用 JSON 資料行。
重要
增強的檢查點不會中斷與開放原始碼 Delta Lake 讀取器的相容性。 不過,將 delta.checkpoint.writeStatsAsJson
設定為 false
可能會影響專屬 Delta Lake 讀取器。 請連絡您的廠商以深入瞭解效能影響。
啟用結構化串流查詢的增強檢查點
如果您的結構化串流工作負載沒有低延遲需求(低於延遲),您可以執行下列 SQL 命令來啟用增強的檢查點:
ALTER TABLE <table-name> SET TBLPROPERTIES
('delta.checkpoint.writeStatsAsStruct' = 'true')
您也可以藉由設定下表屬性來改善檢查點寫入延遲:
ALTER TABLE <table-name> SET TBLPROPERTIES
(
'delta.checkpoint.writeStatsAsStruct' = 'true',
'delta.checkpoint.writeStatsAsJson' = 'false'
)
如果您的應用程式中略過資料並無用處,您可以將這兩個屬性設定為 false。 然後不會收集或寫入任何統計資料。 Databricks 不建議使用此設定。