

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 最佳化寫入效能
<a name="best-practices-write"></a>

本節討論您可以調校的資料表屬性，以最佳化 Iceberg 資料表的寫入效能，不受引擎影響。

## 設定資料表分佈模式
<a name="write-distribution-mode"></a>

Iceberg 提供多種寫入分佈模式，可定義寫入資料在 Spark 任務中的分佈方式。如需可用模式的概觀，請參閱 Iceberg 文件中的[撰寫分佈模式](https://iceberg.apache.org/docs/latest/spark-writes/#writing-distribution-modes)。

對於優先考慮寫入速度的使用案例，特別是在串流工作負載中，請將 `write.distribution-mode`設定為 `none`。這可確保 Iceberg 不會請求額外的 Spark 隨機播放，而且資料會在 Spark 任務中可用時寫入。此模式特別適合 Spark 結構化串流應用程式。

**注意**  
將寫入分佈模式設定為 `none` 往往會產生許多小型檔案，進而降低讀取效能。我們建議定期壓縮，將這些小型檔案合併為適當大小的檔案，以獲得查詢效能。

## 選擇正確的更新策略
<a name="write-update-strategy"></a>

當您的使用案例接受最新資料的較慢讀取操作時，請使用merge-on-read** **策略來最佳化寫入效能。

當您使用merge-on-read，Iceberg 會將更新寫入儲存，並刪除為個別的小型檔案。讀取資料表時，讀取器必須將這些變更與基礎檔案合併，以傳回資料的最新檢視。這會導致讀取操作的效能懲罰，但可加快更新和刪除的寫入速度。一般而言，merge-on-read非常適合具有更新或任務的串流工作負載，這些更新較少，且分散在許多資料表分割區中。

您可以在資料表層級或應用程式端獨立設定merge-on-read組態 (`write.delete.mode`、 `write.update.mode`和 `write.merge.mode`)。

使用merge-on-read需要執行定期壓縮，以防止讀取效能隨著時間降低。壓縮會與現有的資料檔案協調更新和刪除，以建立新的一組資料檔案，從而消除讀取端產生的效能損失。根據預設，除非您將 `delete-file-threshold` 屬性的預設值變更為較小的值，否則 Iceberg 的壓縮不會合併刪除檔案 （請參閱 [Iceberg 文件](https://iceberg.apache.org/docs/latest/spark-procedures/#rewrite_data_files))。若要進一步了解壓縮，請參閱本指南稍後的 [Iceberg 壓縮](best-practices-compaction.md)一節。

## 選擇正確的檔案格式
<a name="write-file-format"></a>

Iceberg 支援以 Parquet、ORC 和 Avro 格式寫入資料。Parquet 是預設格式。Parquet 和 ORC 是單欄式格式，可提供卓越的讀取效能，但寫入速度通常較慢。這代表讀取和寫入效能之間的典型取捨。

如果寫入速度對您的使用案例很重要，例如在串流工作負載中，請考慮在寫入器的選項`Avro`中`write-format`將 設定為 ，以 Avro 格式寫入。由於 Avro 是以資料列為基礎的格式，因此能以較慢的讀取效能提供更快的寫入時間。

為了改善讀取效能，請執行定期壓縮，將小型 Avro 檔案合併並轉換為較大的 Parquet 檔案。壓縮程序的結果由`write.format.default`資料表設定管理。Iceberg 的預設格式為 Parquet，因此如果您在 Avro 中寫入 ，然後執行壓縮，Iceberg 會將 Avro 檔案轉換為 Parquet 檔案。範例如下：

```
spark.sql(f"""
    CREATE TABLE IF NOT EXISTS glue_catalog.{DB_NAME}.{TABLE_NAME} (
        Col_1 float, 
        <<<…other columns…>>
        ts timestamp)
    USING iceberg
    PARTITIONED BY (days(ts))
    OPTIONS (
      'format-version'='2',
      write.format.default'=parquet)
""")

query = df \
    .writeStream \
    .format("iceberg") \
    .option("write-format", "avro") \
    .outputMode("append") \
    .trigger(processingTime='60 seconds') \
    .option("path", f"glue_catalog.{DB_NAME}.{TABLE_NAME}") \
    .option("checkpointLocation", f"s3://{BUCKET_NAME}/checkpoints/iceberg/")

    .start()
```