將資料匯出至 Spanner (反向 ETL)
本文說明如何設定從 BigQuery 到 Spanner 的反向擷取、轉換和載入 (反向 ETL) 工作流程。方法是使用 EXPORT DATA 陳述式,將 BigQuery 資料來源 (包括 Iceberg 資料表) 的資料匯出至 Spanner 資料表。
這項反向 ETL 工作流程結合了 BigQuery 的分析功能,以及 Spanner 的低延遲時間和高處理量。這個工作流程可讓您將資料提供給應用程式使用者,同時避免耗盡 BigQuery 的配額和限制。
事前準備
建立 Spanner 資料庫,並在其中建立資料表,用於接收匯出的資料。
授予 Identity and Access Management (IAM) 角色,讓使用者具備執行本文件中各項工作所需的權限。
如要使用這項功能,請建立 BigQuery Enterprise 或 Enterprise Plus 級預留項目。批次匯出需要
QUERY指派,持續匯出則需要CONTINUOUS指派。
將資料一次性匯出至 Spanner 時,您可以將基準運算單元容量設為零,並啟用自動調度資源功能,降低 BigQuery 運算費用。
必要的角色
如要取得將 BigQuery 資料匯出至 Spanner 所需的權限,請要求管理員在專案中授予您下列 IAM 角色:
-
從 BigQuery 資料表匯出資料:BigQuery 資料檢視者 (
roles/bigquery.dataViewer) -
執行擷取工作:BigQuery 使用者 (
roles/bigquery.user) -
檢查 Spanner 執行個體的參數:Cloud Spanner 檢視者 (
roles/spanner.viewer) -
將資料寫入 Spanner 資料表:Cloud Spanner 資料庫使用者 (
roles/spanner.databaseUser)
如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。
限制
Assured Workloads 不支援這項功能。
下列 BigQuery 資料類型在 Spanner 中沒有對應類型,因此不支援:
| Spanner 資料庫方言 | 不支援的 BigQuery 類型 |
|---|---|
| 所有方言 |
|
| GoogleSQL |
|
匯出的資料列大小上限不得超過 1 MiB。
Spanner 會在匯出期間強制執行參照完整性。如果目標資料表是另一個資料表的子項 (INTERLEAVE IN PARENT),或目標資料表有外鍵限制,系統會在匯出期間驗證外鍵和父項索引鍵。如果匯出的資料列寫入含有 INTERLEAVE IN PARENT 的資料表,且父項資料列不存在,匯出作業就會失敗,並顯示「Parent row is missing. Row cannot be written」錯誤。如果匯出的資料列寫入具有外鍵限制的資料表,且參照的鍵不存在,匯出作業就會失敗,並顯示「Foreign key constraint is violated」錯誤。匯出至多個資料表時,建議您依序匯出,確保匯出作業能維持參照完整性。這通常表示要先匯出父項資料表和外鍵參照的資料表,再匯出參照這些資料表的資料表。
如果匯出作業的目標資料表有外鍵限制,或是另一個資料表的子項 (INTERLEAVE IN PARENT),則必須先填入父項資料表,再匯出子項資料表,且父項資料表應包含所有對應的鍵。如果父項資料表不具備一組完整的相關索引鍵,則嘗試匯出子項資料表時會失敗。
BigQuery 工作 (例如將資料擷取至 Spanner 的工作) 的執行時間上限為 6 小時。如要瞭解如何最佳化大型擷取工作,請參閱「匯出最佳化」。或者,您也可以考慮將輸入內容分割成個別資料區塊,並匯出為個別擷取工作。
匯出至 Spanner 僅適用於 BigQuery Enterprise 或 Enterprise Plus 版本。不支援 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(選用):寫入要求的優先順序。允許的值:LOW、MEDIUM、HIGH。預設值:MEDIUM。TAG(選用):要求標記,用於在 Spanner 監控中識別匯出工具流量。預設值:bq_export。
匯出查詢條件
如要將查詢結果匯出至 Spanner,結果必須符合下列規定:
- 結果集中的所有資料欄都必須存在於目的地資料表中,且類型必須相符或可轉換。
- 結果集必須包含目的地資料表的所有
NOT NULL欄。 - 資料欄值不得超過 Spanner 資料表內的資料大小限制。
- 匯出至 Spanner 前,必須將所有不支援的資料欄類型轉換為支援的類型。
類型轉換
為方便使用,Spanner 匯出工具會自動套用下列類型轉換:
| BigQuery 類型 | Spanner 類型 |
|---|---|
| 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 資料列 (不保證是哪一列)。
使用 CLOUD_RESOURCE 連線匯出
您可以將寫入權限委派給 BigQuery CLOUD_RESOURCE 連線,以便執行匯出作業,而不必直接授予使用者 Spanner 資料庫的存取權。
使用 CLOUD_RESOURCE 連線匯出至 Spanner 前,請先完成下列事項:
建立連線
您可以建立或使用現有的 CLOUD_RESOURCE 連線,連線至 Spanner。
控制台
前往「BigQuery」頁面。
點選左側窗格中的 「Explorer」。

如果沒有看到左側窗格,請按一下 「Expand left pane」(展開左側窗格),開啟窗格。
在「Explorer」窗格中展開專案名稱,然後點選「Connections」(連線)。
在「Connections」(連線) 頁面,按一下「Create connection」(建立連線)。
在「連線類型」部分,選擇「Vertex AI 遠端模型、遠端函式、BigLake 和 Spanner (Cloud 資源)」。
在「連線 ID」欄位輸入連線名稱。
在「位置類型」部分,選取連線位置。連線應與資料集等其他資源位於相同位置。
點選「建立連線」。
點選「前往連線」。
在「連線資訊」窗格中,複製服務帳戶 ID,以便在後續步驟中使用。
SQL
前往 Google Cloud 控制台的「BigQuery」頁面。
在查詢編輯器中輸入下列陳述式:
CREATE CONNECTION [IF NOT EXISTS] `CONNECTION_NAME` OPTIONS ( connection_type = "CLOUD_RESOURCE", friendly_name = "FRIENDLY_NAME", description = "DESCRIPTION" );
替換下列內容:
-
CONNECTION_NAME:連線名稱,格式為PROJECT_ID.LOCATION.CONNECTION_ID、LOCATION.CONNECTION_ID或CONNECTION_ID。如果省略專案或位置,系統會根據執行陳述式的專案和位置推論。 -
FRIENDLY_NAME(選用):連線的描述性名稱。 -
DESCRIPTION(選用):連線說明。
-
按一下「 執行」。
如要進一步瞭解如何執行查詢,請參閱「執行互動式查詢」。
bq
在指令列環境中建立連線:
bq mk --connection --location=REGION --project_id=PROJECT_ID \ --connection_type=CLOUD_RESOURCE CONNECTION_ID
--project_id參數會覆寫預設專案。更改下列內容:
REGION:連線區域PROJECT_ID:您的 Google Cloud 專案 IDCONNECTION_ID:連線 ID
建立連線資源時,BigQuery 會建立專屬的系統服務帳戶,並與連線建立關聯。
疑難排解:如果收到下列連線錯誤,請更新 Google Cloud SDK:
Flags parsing error: flag --connection_type=CLOUD_RESOURCE: value should be one of...
擷取並複製服務帳戶 ID,以便在後續步驟中使用:
bq show --connection PROJECT_ID.REGION.CONNECTION_ID
輸出結果會與下列內容相似:
name properties 1234.REGION.CONNECTION_ID {"serviceAccountId": "connection-1234-9u56h9@gcp-sa-bigquery-condel.iam.gserviceaccount.com"}
Python
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Python 設定操作說明進行操作。詳情請參閱 BigQuery Python API 參考文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。
Node.js
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Node.js 設定操作說明進行操作。詳情請參閱 BigQuery Node.js API 參考文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。
Terraform
使用 google_bigquery_connection 資源。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。
下列範例會在 US 區域建立名為 my_cloud_resource_connection 的 Cloud 資源連結:
如要在 Google Cloud 專案中套用 Terraform 設定,請完成下列各節的步驟。
準備 Cloud Shell
- 啟動 Cloud Shell。
-
設定要套用 Terraform 設定的預設 Google Cloud 專案。
每個專案只需執行這個指令一次,而且可以在任何目錄中執行。
export GOOGLE_CLOUD_PROJECT=PROJECT_ID
如果您在 Terraform 設定檔中設定明確的值,環境變數就會遭到覆寫。
準備目錄
每個 Terraform 設定檔都必須有自己的目錄 (也稱為根模組)。
-
在 Cloud Shell 中建立目錄,並在該目錄中建立新檔案。檔案名稱必須有
.tf副檔名,例如main.tf。在本教學課程中,這個檔案稱為main.tf。mkdir DIRECTORY && cd DIRECTORY && touch main.tf
-
如果您正在進行教學課程,可以複製每個章節或步驟中的程式碼範例。
將程式碼範例複製到新建立的
main.tf。您也可以從 GitHub 複製程式碼。如果 Terraform 程式碼片段是端對端解決方案的一部分,建議您採用這種做法。
- 請查看並修改範例參數,以便套用至您的環境。
- 儲存變更。
-
初始化 Terraform。每個目錄只需執行一次這項操作。
terraform init
如要使用最新版 Google 供應商,請視需要加入
-upgrade選項:terraform init -upgrade
套用變更
-
查看設定,確認 Terraform 要建立或更新的資源符合預期:
terraform plan
視需要修正設定。
-
執行下列指令,並在提示中輸入
yes,套用 Terraform 設定:terraform apply
等待 Terraform 顯示「Apply complete!」訊息。
- 開啟 Google Cloud 專案即可查看結果。在 Google Cloud 控制台的使用者介面中,前往資源頁面,確認 Terraform 已建立或更新資源。
建立連線後,請開啟連線。在「連線資訊」窗格中,複製服務帳戶 ID。設定連線權限時,您會需要這個 ID。建立連線資源時,BigQuery 會建立專屬的系統服務帳戶,並與連線建立關聯。
設定存取權
您必須將 Spanner 執行個體或資料庫的寫入權限,授予與新連結相關聯的服務帳戶。建議您使用 Cloud Spanner 資料庫使用者 (roles/spanner.databaseUser) 預先定義的 IAM 角色。執行這些步驟時,需要用到您在建立連線時複製的服務帳戶 ID。
如要將資料庫層級角色的存取權授予服務帳戶,請按照下列步驟操作:
前往 Spanner 執行個體頁面。
按一下包含資料庫的執行個體名稱。
在「Overview」(總覽) 分頁中,選取資料庫的核取方塊。
系統會隨即顯示「Info panel」(資訊面板) 對話方塊。按一下「Add principal」(新增主體)。
在「新增主體」部分,輸入先前複製的服務帳戶 ID。
在「Select a role」(選取角色) 欄位中,選取具備
spanner.databases.write權限的角色。建議您使用 Cloud Spanner 資料庫使用者角色。按一下 [儲存]。
使用 CLOUD_RESOURCE 連線執行匯出作業
建立連線並授予適當存取權後,您可以使用 CLOUD_RESOURCE 連線執行匯出作業。下列範例顯示使用 CLOUD_RESOURCE 連線匯出的 EXPORT 指令。
EXPORT DATA WITH CONNECTION `PROJECT_ID.LOCATION.CONNECTION_NAME` OPTIONS ( uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID", format='CLOUD_SPANNER', spanner_options="""{ "table": "SPANNER_TABLE_NAME" }""" ) AS SELECT * FROM my_bq_dataset.table1;
替換下列內容:
PROJECT_ID:您 Google Cloud 專案的名稱。LOCATION:建立連線的位置,例如us。CONNECTION_NAME:用於執行匯出作業的連線名稱,例如myconnection。INSTANCE_ID:Spanner 資料庫執行個體的名稱。DATABASE_ID:Spanner 資料庫的名稱。SPANNER_TABLE_NAME:現有目的地 Spanner 資料表的名稱。
持續匯出
如要持續處理匯出查詢,請參閱建立持續查詢的操作說明和程式碼範例。
匯出最佳化
如要最佳化從 BigQuery 匯出記錄至 Spanner 的作業,可以嘗試下列做法:
增加 Spanner 目的地執行個體中的節點數量。在匯出作業初期,增加執行個體中的節點數量,可能不會立即提高匯出處理量。Spanner 執行依負載分割時,可能會稍微延遲。採用負載分割後,匯出處理量會增加並趨於穩定。使用
EXPORT DATA陳述式批次處理資料,可最佳化 Spanner 的寫入作業。詳情請參閱「效能總覽」。在
spanner_options中指定HIGH優先順序。如果 Spanner 執行個體已啟用自動調度資源功能,設定HIGH優先順序有助於確保 CPU 使用率達到觸發調度資源的必要門檻。這樣一來,自動配置器就能根據匯出負載新增運算資源,進而提高整體匯出處理量。以下範例顯示 Spanner 匯出指令設為
HIGH優先順序: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": "LOW" }""" )
避免排序查詢結果。如果結果集包含所有主鍵欄,匯出工具會自動排序目的地資料表的主鍵,簡化寫入作業並盡可能減少爭用。
如果目的地資料表的主鍵包含生成資料欄,請在查詢中加入生成資料欄的運算式,確保匯出的資料能正確排序及分批。
舉例來說,在下列 Spanner 結構定義中,
SaleYear和SaleMonth是產生的資料欄,構成 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資料表,其主鍵使用產生的資料欄。為提高寫入效能,查詢會包含與產生的SaleYear和SaleMonth資料欄相符的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 資料進行 shard:
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 節點 (1,000 個處理器單元) 和最低的 BigQuery 預留運算單元開始。例如 100 個運算單元,或 0 個基準運算單元,並啟用自動調度資源功能。如果匯出作業小於 100 GB,這項設定通常會在 6 小時的工作限制內完成。如果匯出項目超過 100 GB,請視需要擴充 Spanner 節點和 BigQuery 預留運算單元,提高處理量。處理量會以每個節點約 5 MiB/s 的速度擴充。
定價
使用 EXPORT DATA 陳述式將資料匯出至 Spanner 時,系統會依據 BigQuery 運算資源定價計費。
如要使用持續查詢,持續將資料匯出至 Spanner,您必須具備 BigQuery Enterprise 或 Enterprise Plus 版本運算單元預留項目,以及使用 CONTINUOUS 工作類型的預留項目指派作業。
如果 BigQuery Export 匯出至 Spanner 的作業跨越區域邊界,則會依資料擷取費率計費。詳情請參閱「BigQuery 定價」一文。為避免產生資料移轉費用,請確保 BigQuery 匯出作業與 Spanner 預設領導者在相同區域執行。
資料匯出後,系統會向您收取在 Spanner 儲存資料的費用。詳情請參閱「Spanner 定價」。