將資料匯出至 Spanner (反向 ETL)

本文說明如何設定從 BigQuery 到 Spanner 的反向擷取、轉換及載入 (反向 ETL) 工作流程。您可以使用 EXPORT DATA 陳述式,從 BigQuery 資料來源 (包括 Iceberg 資料表) 匯出資料至 Spanner 資料表。

這項反向 ETL 工作流程結合了 BigQuery 的分析功能,以及 Spanner 的低延遲和高總處理量特性。這個工作流程可讓您將資料提供給應用程式使用者,而不會超出 BigQuery 的配額和限制。

事前準備

必要的角色

如要取得將 BigQuery 資料匯出至 Spanner 所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

限制

  • Assured Workloads 不支援這項功能。

  • 下列 BigQuery 資料類型在 Spanner 中沒有對應項目,因此不支援:

Spanner 資料庫方言 不支援的 BigQuery 類型
所有方言
  • STRUCT
  • GEOGRAPHY
  • DATETIME
  • RANGE
  • TIME
GoogleSQL
  • BIGNUMERIC:支援的 NUMERIC 類型不夠廣泛。建議在查詢中將明確轉換新增至 NUMERIC 型別。
  • 匯出資料列的大小上限為 1 MiB。

  • Spanner 會在匯出期間強制執行參照完整性。 如果目標資料表是另一個資料表的子項 (INTERLEAVE IN PARENT),或目標資料表有外鍵限制,系統會在匯出期間驗證外鍵和父項鍵。如果匯出的資料列寫入的資料表具有 INTERLEAVE IN PARENT,但父項資料列不存在,匯出作業就會失敗,並顯示「Parent row is missing. 無法寫入資料列」錯誤。如果匯出的資料列寫入的資料表含有外鍵限制,且參照的鍵不存在,匯出作業就會失敗,並顯示「違反外鍵限制」錯誤。匯出至多個資料表時,建議您依序匯出,確保匯出作業維持參照完整性。這通常表示先匯出父項資料表和外鍵參照的資料表,再匯出參照這些資料表的資料表。

    如果匯出目標資料表有外鍵限制,或是另一個資料表的子項 (INTERLEAVE IN PARENT),則必須先填入父項資料表,再匯出子項資料表,且父項資料表應包含所有對應的鍵。如果父項資料表沒有完整的相關鍵集,嘗試匯出子項資料表就會失敗。

  • BigQuery 工作 (例如擷取至 Spanner 的工作) 的最長執行時間為 6 小時。如要瞭解如何最佳化大型擷取工作,請參閱「匯出最佳化」。或者,您也可以考慮將輸入內容分割成個別資料區塊,然後以個別擷取工作匯出。

  • 只有 BigQuery Enterprise 或 Enterprise Plus 版本支援匯出至 Spanner。不支援 BigQuery Standard 版和隨選運算。

  • 您無法使用持續查詢,將資料匯出至具有自動產生主鍵的 Spanner 資料表。

  • 您無法使用連續查詢,將資料匯出至 PostgreSQL 方言資料庫中的 Spanner 資料表。

  • 使用連續查詢匯出至 Spanner 資料表時,請務必選擇與 BigQuery 資料表中單調遞增整數不相符的主鍵。否則可能會導致匯出作業發生效能問題。如要瞭解 Spanner 中的主鍵,以及如何減輕這些效能問題,請參閱「選擇主鍵」。

使用「spanner_options」選項設定匯出作業

您可以使用 spanner_options 選項指定目標 Spanner 資料庫和資料表。設定會以 JSON 字串的形式表示,如下列範例所示:

EXPORT DATA OPTIONS(
   uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format='CLOUD_SPANNER',
   spanner_options = """{
      "table": "TABLE_NAME",
      "change_timestamp_column": "CHANGE_TIMESTAMP",
      "priority": "PRIORITY",
      "tag": "TAG",
   }"""
)

更改下列內容:

  • PROJECT_ID: Google Cloud 專案的名稱。
  • INSTANCE_ID:資料庫執行個體的名稱。
  • DATABASE_ID:資料庫名稱。
  • TABLE_NAME:現有目標資料表的名稱。
  • CHANGE_TIMESTAMP:目的地 Spanner 資料表中的 TIMESTAMP 型別資料欄名稱。這個選項會在匯出期間使用,追蹤最新列更新的時間戳記。指定這個選項後,匯出作業會先讀取 Spanner 資料表中的資料列,確保只寫入最新的資料列更新。執行持續匯出時,建議指定 TIMESTAMP 類型資料欄,因為相同主鍵的資料列變更順序非常重要。
  • PRIORITY (選用): 寫入要求的優先順序。允許的值:LOWMEDIUMHIGH。預設值:MEDIUM
  • TAG (選用): 要求標記 ,有助於在 Spanner 監控中識別匯出工具流量。 預設值為 bq_export

匯出查詢的規定

如要將查詢結果匯出至 Spanner,結果必須符合下列條件:

  • 結果集中的所有資料欄都必須存在於目的地資料表中,且類型必須相符或可轉換
  • 結果集必須包含目的地資料表的所有 NOT NULL 欄。
  • 資料欄值不得超過資料表中的 Spanner 資料大小限制
  • 匯出至 Spanner 前,必須將所有不支援的資料欄類型轉換為支援的類型。

類型轉換

為方便使用,Spanner 匯出工具會自動套用下列型別轉換:

BigQuery 類型 扳手類型
BIGNUMERIC NUMERIC (僅限 PostgreSQL 方言)
FLOAT64 FLOAT32
BYTES PROTO
INT64 ENUM

匯出資料

您可以使用 EXPORT DATA 陳述式,將資料從 BigQuery 資料表匯出至 Spanner 資料表。

下列範例會從名為 mydataset.table1 的資料表匯出所選欄位:

EXPORT DATA OPTIONS (
  uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format='CLOUD_SPANNER',
  spanner_options="""{ "table": "TABLE_NAME" }"""
)
AS SELECT * FROM mydataset.table1;

更改下列內容:

  • PROJECT_ID: Google Cloud 專案名稱
  • INSTANCE_ID:資料庫執行個體的名稱
  • DATABASE_ID:資料庫名稱
  • TABLE_NAME:現有目的地資料表的名稱

匯出具有相同 rowkey 值的多個結果

匯出含有多個相同 rowkey 值的資料列時,寫入 Spanner 的值會位於同一個 Spanner 資料列。匯出作業產生的 Spanner 資料列集只會包含單一相符的 BigQuery 資料列 (無法保證是哪一個)。

持續匯出

如要持續處理匯出查詢,請參閱建立持續查詢的操作說明和範例程式碼

匯出最佳化

如要盡量縮短從 BigQuery 匯出記錄至 Spanner 的時間,可以嘗試下列做法:

  • 增加 Spanner 目的地執行個體中的節點數量。在匯出作業的初期階段,增加執行個體中的節點數量可能不會立即提高匯出輸送量。Spanner 執行以負載為準的分割時,可能會稍微延遲。依負載分割可提高匯出作業的處理量,並維持穩定。使用 EXPORT DATA 陳述式批次處理資料,以最佳化寫入 Spanner 的作業。詳情請參閱「成效總覽」。

  • spanner_options 中指定 HIGH 優先順序。如果 Spanner 執行個體已啟用自動調度資源功能,設定 HIGH 優先順序有助於確保 CPU 使用率達到觸發調度資源的必要門檻。這樣一來,自動調度器就能根據匯出負載新增運算資源,進而提升整體匯出輸送量。

    以下範例顯示設為 HIGH 優先順序的 Spanner 匯出指令:

    EXPORT DATA OPTIONS (
      uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
      format='CLOUD_SPANNER',
      spanner_options="""{ "table": "TABLE_NAME", "priority": "HIGH" }"""
    )
  • 避免排序查詢結果。如果結果集包含所有主鍵欄,匯出工具會自動排序目的地表格的主鍵,以簡化寫入作業並減少爭用。

    如果目的地資料表的主鍵包含產生的資料欄,請將產生的資料欄運算式新增至查詢,確保匯出的資料經過適當排序和批次處理。

    舉例來說,在下列 Spanner 結構定義中,SaleYearSaleMonth 是構成 Spanner 主鍵開頭的產生資料欄:

    CREATE TABLE Sales (
      SaleId STRING(36) NOT NULL,
      ProductId INT64 NOT NULL,
      SaleTimestamp TIMESTAMP NOT NULL,
      Amount FLOAT64,
      -- Generated columns
      SaleYear INT64 AS (EXTRACT(YEAR FROM SaleTimestamp)) STORED,
      SaleMonth INT64 AS (EXTRACT(MONTH FROM SaleTimestamp)) STORED,
    ) PRIMARY KEY (SaleYear, SaleMonth, SaleId);

    從 BigQuery 匯出資料至 Spanner 資料表時,如果主鍵使用產生的資料欄,建議 (但非必要) 在 EXPORT DATA 查詢中加入這些產生資料欄的運算式。這樣 BigQuery 就能正確預先排序資料,這對有效率地批次處理資料並寫入 Spanner 至關重要。EXPORT DATA 陳述式中產生的資料欄值不會在 Spanner 中提交,因為這些值是由 Spanner 自動產生,但會用於最佳化匯出作業。

    下列範例會將資料匯出至 Spanner Sales 資料表,該資料表的主鍵使用產生的資料欄。為提升寫入效能,查詢會包含與產生的 SaleYearSaleMonth 資料欄相符的 EXTRACT 運算式,讓 BigQuery 在匯出資料前預先排序:

    EXPORT DATA OPTIONS (
      uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
      format='CLOUD_SPANNER',
      spanner_options="""{ "table": "Sales" }"""
    )
    AS SELECT
      s.SaleId,
      s.ProductId,
      s.SaleTimestamp,
      s.Amount,
      -- Add expressions that match the generated columns in the Spanner PK
      EXTRACT(YEAR FROM s.SaleTimestamp) AS SaleYear,
      EXTRACT(MONTH FROM s.SaleTimestamp) AS SaleMonth
    FROM my_dataset.sales_export AS s;
  • 為避免工作長時間執行,請依分區匯出資料。使用分區鍵 (例如查詢中的時間戳記) 將 BigQuery 資料分片:

    EXPORT DATA OPTIONS (
      uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
      format='CLOUD_SPANNER',
      spanner_options="""{ "table": "TABLE_NAME", "priority": "MEDIUM" }"""
    )
    AS SELECT *
    FROM 'mydataset.table1' d
    WHERE
    d.timestamp >= TIMESTAMP '2025-08-28T00:00:00Z' AND
    d.timestamp < TIMESTAMP '2025-08-29T00:00:00Z';

    這樣查詢就能在 6 小時的工作執行時間內完成。如要進一步瞭解這些限制,請參閱查詢工作限制

  • 如要提升資料載入效能,請在匯入資料的 Spanner 表格中捨棄索引。然後在匯入完成後重新建立。

  • 建議您先從一個 Spanner 節點 (1000 個處理器單元) 和最少的 BigQuery 預留時段開始。例如 100 個運算單元,或 0 個基準運算單元 (搭配自動調度資源)。如果匯出資料量小於 100 GB,這項設定通常會在 6 小時的工作限制內完成。如要匯出超過 100 GB 的資料,請視需要增加 Spanner 節點和 BigQuery 運算單元預留量,以提高輸送量。每個節點的處理量約為每秒 5 MiB。

定價

使用 EXPORT DATA 陳述式將資料匯出至 Spanner 時,系統會按照 BigQuery 容量運算定價計費。

如要使用持續查詢功能,將資料持續匯出至 Spanner,您必須擁有 BigQuery Enterprise 或 Enterprise Plus 版的運算單元保留項目,以及使用 CONTINUOUS 工作類型的保留項目指派作業

如果 BigQuery 匯出至 Spanner 的資料跨越區域界線,系統會按照資料擷取費率收費。詳情請參閱 BigQuery 計價方式一文。為避免資料移轉費用,請確保 BigQuery 匯出作業與 Spanner 預設領導者位於相同區域。持續查詢匯出作業不支援跨區域邊界的匯出作業。

匯出資料後,系統會因您在 Spanner 中儲存資料而向您收取費用。詳情請參閱 Spanner 定價