本頁面提供將開放原始碼 PostgreSQL 資料庫遷移至 Spanner 的指南。
遷移作業包括下列工作:
- 將 PostgreSQL 結構定義對應至 Spanner 結構定義。
- 建立 Spanner 執行個體、資料庫和結構定義。
- 重構應用程式,以便與 Spanner 資料庫搭配使用。
- 遷移資料。
- 驗證新系統並將其移至實際運作狀態。
本頁面也提供一些使用 MusicBrainz PostgreSQL 資料庫中資料表的範例結構定義。
將 PostgreSQL 結構定義對應至 Spanner
如果要將資料庫從 PostgreSQL 移至 Spanner,首先要決定哪些結構定義必須變更。使用 pg_dump
建立資料定義語言 (DDL) 陳述式,以定義 PostgreSQL 資料庫中的物件,然後按照下列章節所述修改陳述式。更新 DDL 陳述式後,請使用這些陳述式在 Spanner 執行個體中建立資料庫。
資料類型
下表說明 PostgreSQL 資料類型和 Spanner 資料類型之間的對應關係。將 DDL 陳述式中的資料類型從 PostgreSQL 資料類型更新為 Spanner 資料類型。
PostgreSQL | Spanner |
---|---|
Bigint
|
INT64 |
Bigserial
|
INT64 |
bit [ (n) ] |
ARRAY |
bit varying [ (n) ]
|
ARRAY |
Boolean
|
BOOL |
box |
ARRAY |
bytea |
BYTES |
character [ (n) ]
|
STRING |
character varying [ (n) ]
|
STRING |
cidr |
STRING ,使用標準 CIDR 標記法。 |
circle |
ARRAY |
date |
DATE |
double precision
|
FLOAT64 |
inet |
STRING |
Integer
|
INT64 |
interval[ fields ] [ (p) ] |
如果以毫秒為單位儲存則為 INT64 ;若採用應用程式定義的間隔格式則為 STRING 。 |
json |
STRING |
jsonb |
JSON |
line |
ARRAY |
lseg |
ARRAY |
macaddr |
STRING ,使用標準的 MAC 位址標記法。 |
money |
INT64 ,若使用任意有效位數則為 STRING 。 |
numeric [ (p, s) ]
|
在 PostgreSQL 中,NUMERIC 和 DECIMAL 資料類型最多支援 217 位精確度和 214-1 的小數位數,如資料欄宣告中所定義。Spanner NUMERIC 資料類型最多支援 38 位精確度和 9 位小數位數。如果您需要更高的精確度,請參閱「儲存任意精確度數值資料」一文,瞭解替代機制。 |
path |
ARRAY |
pg_lsn |
這是 PostgreSQL 專屬的資料類型,因此沒有對應的 Spanner 資料類型。 |
point |
ARRAY |
polygon |
ARRAY |
Real
|
FLOAT64 |
Smallint
|
INT64 |
Smallserial
|
INT64 |
Serial
|
INT64 |
text |
STRING |
time [ (p) ] [ without time zone ] |
STRING ,使用 HH:MM:SS.sss 標記法。 |
time [ (p) ] with time zone
|
STRING ,使用 HH:MM:SS.sss+ZZZZ 標記法。或者,您可以將這項資料拆分為兩個欄,一個是 TIMESTAMP 類型,另一個則是用於儲存時區的欄。 |
timestamp [ (p) ] [ without time zone ] |
沒有對應項目。您可以視需要將其儲存為 STRING 或 TIMESTAMP 。 |
timestamp [ (p) ] with time zone
|
TIMESTAMP |
tsquery |
沒有對應項目。改成在應用程式中定義儲存機制。 |
tsvector |
沒有對應項目。改成在應用程式中定義儲存機制。 |
txid_snapshot |
沒有對應項目。改成在應用程式中定義儲存機制。 |
uuid |
STRING 或 BYTES |
xml |
STRING |
主要金鑰
針對您在 Spanner 資料庫中經常執行附加操作的資料表,請避免使用單調增加或減少的主鍵,因為此方法會在寫入時造成資源使用率不均。請改為修改 DDL CREATE TABLE
陳述式,讓其使用支援的主鍵策略。如果您使用 PostgreSQL 功能 (例如 UUID
資料類型或函式、SERIAL
資料類型、IDENTITY
欄或序列),可以使用我們建議的自動產生的主要遷移策略。
請注意,指定主鍵後,除非刪除並重新建立資料表,否則無法新增或移除主鍵資料欄,也無法稍後變更主鍵值。如要進一步瞭解如何指定主鍵,請參閱「結構定義和資料模型 - 主鍵」。
遷移期間,您可能需要保留一些現有的單調增加整數索引鍵。如果您必須將這些類型的索引鍵保存於經常更新的資料表上,並且會對這些索引鍵執行大量操作,那麼您可以在現有索引鍵前面加上虛擬隨機號碼,以避免造成資源使用率不均。這個技巧會讓 Spanner 重新分配資料列。如要進一步瞭解如何使用此方法,請參閱 DBA 必須瞭解的 Spanner 知識 (第 1 部分):索引鍵與索引。
外鍵和參考完整性
瞭解 Spanner 中的外鍵支援功能。
索引
PostgreSQL B-Tree 索引類似 Spanner 中的次要索引。在 Spanner 資料庫中,您可以使用次要索引為經常搜尋的資料欄建立索引,如此可提升效能並取代資料表中指定的任何 UNIQUE
限制。比方說,如果您的 PostgreSQL DDL 有下方這個陳述式:
CREATE TABLE customer (
id CHAR (5) PRIMARY KEY,
first_name VARCHAR (50),
last_name VARCHAR (50),
email VARCHAR (50) UNIQUE
);
那麼您就應該在 Spanner DDL 中使用下列陳述式:
CREATE TABLE customer (
id STRING(5),
first_name STRING(50),
last_name STRING(50),
email STRING(50)
) PRIMARY KEY (id);
CREATE UNIQUE INDEX customer_emails ON customer(email);
您可以在 psql
中執行 \di
元指令,找出任何 PostgreSQL 資料表的索引。
決定好您所需的索引後,即可新增 CREATE INDEX
陳述式予以建立。請遵循「建立索引」的指示操作。
Spanner 會將索引實作為資料表,因此為單調增加的資料欄 (例如包含 TIMESTAMP
資料的資料欄) 建立索引可能會造成資源使用率不均。如要進一步瞭解如何避免資源使用率不均,請參閱 DBA 必須瞭解的 Spanner 知識 (第 1 部分):索引鍵與索引。
檢查限制條件
其他資料庫物件
您必須在應用程式邏輯中建立下列物件的功能:
- 資料檢視
- 觸發條件
- 預存程序
- 使用者定義的函式 (UDF)
- 使用
serial
資料類型做為序列產生器的資料欄
將此功能遷移到應用程式邏輯時,請注意以下事項:
- 您必須將您使用的任何 SQL 陳述式從 PostgreSQL SQL 方言遷移到 GoogleSQL 方言。
- 如果您使用游標,則可重新執行查詢以使用偏移與限制。
建立 Spanner 執行個體
當您更新 DDL 陳述式以符合 Spanner 結構定義規定之後,請使用該陳述式在 Spanner 中建立資料庫。
建立 Spanner 執行個體。請遵循「執行個體」中的指示操作,找出能夠支援效能目標的地區設定和運算能力。
使用 Google Cloud 主控台或
gcloud
指令列工具建立資料庫:
主控台
- 前往「Instances」(執行個體) 頁面
- 按一下要在其中建立範例資料庫的執行個體名稱,以開啟「Instance details」(執行個體詳細資料) 頁面。
- 按一下 [Create Database] (建立資料庫)。
- 輸入資料庫的名稱,然後按一下「Continue」(繼續)。
- 在「Define your database schema」(定義資料庫結構定義) 區段中,切換「Edit as text」 (以文字形式編輯) 控制項。
- 複製 DDL 陳述式並將其貼到「DDL statements」(DDL 陳述式) 欄位。
- 按一下 [建立]。
gcloud
- 安裝 gcloud CLI。
- 使用
gcloud spanner databases create
指令建立資料庫:gcloud spanner databases create DATABASE_NAME --instance=INSTANCE_NAME --ddl='DDL1' --ddl='DDL2'
- DATABASE_NAME 是資料庫名稱。
- INSTANCE_NAME 是您建立的 Spanner 例項。
- DDLn 是您修改過的 DDL 陳述式。
建立資料庫後,請遵循「套用身分與存取權管理角色」中的指示建立使用者帳戶,並且向 Spanner 執行個體和資料庫授予權限。
重構應用程式和資料存取層
您不僅需要程式碼來取代上述資料庫物件,還必須新增應用程式邏輯,才能處理下列功能:
- 雜湊主鍵,以用於寫入連續索引鍵,以及用於對連續索引鍵具有高寫入速率的資料表。
- 驗證資料,不包含
CHECK
限制。 - 交錯資料表或應用程式邏輯未涵蓋的參考完整性檢查,其中包括 PostgreSQL 結構定義中的觸發條件處理的功能。
建議您在重構期間使用下列程序:
- 找出所有可存取資料庫的應用程式程式碼,然後將其重構為單一模組或程式庫。如此一來,您就能完全掌握哪些程式碼可存取資料庫,並因此清楚地知道要修改哪些程式碼。
- 編寫可在 Spanner 執行讀取和寫入作業的程式碼,為讀取及寫入 PostgreSQL 的原始程式碼提供平行功能。在寫入期間,請更新整個資料列,而非只更新已變更的資料欄,以確保 Spanner 中的資料與 PostgreSQL 中的資料相同。
- 編寫程式碼,取代 Spanner 中未提供的資料庫物件和函式功能。
遷移資料
建立 Spanner 資料庫並重構應用程式程式碼後,即可將資料遷移至 Spanner。
- 使用 PostgreSQL
COPY
指令將資料傾印至 .csv 檔案。 將 .csv 檔案上傳至 Cloud Storage。
- 建立 Cloud Storage 值區。
- 按一下 Cloud Storage 主控台中的值區名稱即可開啟值區瀏覽器。
- 按一下 [Upload Files] (上傳檔案)。
- 前往包含 .csv 檔案的目錄並選取這些檔案。
- 按一下「開啟」。
建立應用程式,以便將資料匯入 Spanner。此應用程式可以使用 Dataflow,也可以直接使用用戶端程式庫。為了獲得最佳效能,請務必遵循載入大量資料最佳做法中的指示操作。
測試
針對 Spanner 執行個體測試所有應用程式功能,以確認這些功能如預期運作。執行實際運作等級的工作負載,確保效能符合您的需求。視需要更新運算能力,以達到您想要的效能目標。
移至新系統
完成初始應用程式測試之後,請使用下列其中一個程序來啟用新系統。離線遷移是最簡單的遷移方式。但是此方法會讓您有一段時間無法使用應用程式,若稍後發現資料有問題也無法復原。如要執行離線遷移:
- 刪除 Spanner 資料庫中的所有資料。
- 關閉以 PostgreSQL 資料庫為目標的應用程式。
- 從 PostgreSQL 資料庫匯出所有資料,再依據遷移概覽的說明將其匯入 Spanner 資料庫。
啟動以 Spanner 資料庫為目標的應用程式。
您也可以採用即時遷移,但這樣做必須大幅變更您的應用程式才能支援遷移作業。
結構定義遷移範例
下方範例說明在 MusicBrainz PostgreSQL 資料庫結構定義中建立幾個資料表的 CREATE TABLE
陳述式。每個範例均包含 PostgreSQL 結構定義和 Spanner 結構定義。
artist_credit table
GoogleSQL
CREATE TABLE artist_credit (
hashed_id STRING(4),
id INT64,
name STRING(MAX) NOT NULL,
artist_count INT64 NOT NULL,
ref_count INT64,
created TIMESTAMP OPTIONS (
allow_commit_timestamp = true
),
) PRIMARY KEY(hashed_id, id);
PostgreSQL
CREATE TABLE artist_credit (
id SERIAL,
name VARCHAR NOT NULL,
artist_count SMALLINT NOT NULL,
ref_count INTEGER DEFAULT 0,
created TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
recording table
GoogleSQL
CREATE TABLE recording (
hashed_id STRING(36),
id INT64,
gid STRING(36) NOT NULL,
name STRING(MAX) NOT NULL,
artist_credit_hid STRING(36) NOT NULL,
artist_credit_id INT64 NOT NULL,
length INT64,
comment STRING(255) NOT NULL,
edits_pending INT64 NOT NULL,
last_updated TIMESTAMP OPTIONS (
allow_commit_timestamp = true
),
video BOOL NOT NULL,
) PRIMARY KEY(hashed_id, id);
PostgreSQL
CREATE TABLE recording (
id SERIAL,
gid UUID NOT NULL,
name VARCHAR NOT NULL,
artist_credit INTEGER NOT NULL, -- references artist_credit.id
length INTEGER CHECK (length IS NULL OR length > 0),
comment VARCHAR(255) NOT NULL DEFAULT '',
edits_pending INTEGER NOT NULL DEFAULT 0 CHECK (edits_pending >= 0),
last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
video BOOLEAN NOT NULL DEFAULT FALSE
);
recording-alias table
GoogleSQL
CREATE TABLE recording_alias (
hashed_id STRING(36) NOT NULL,
id INT64 NOT NULL,
alias_id INT64,
name STRING(MAX) NOT NULL,
locale STRING(MAX),
edits_pending INT64 NOT NULL,
last_updated TIMESTAMP NOT NULL OPTIONS (
allow_commit_timestamp = true
),
type INT64,
sort_name STRING(MAX) NOT NULL,
begin_date_year INT64,
begin_date_month INT64,
begin_date_day INT64,
end_date_year INT64,
end_date_month INT64,
end_date_day INT64,
primary_for_locale BOOL NOT NULL,
ended BOOL NOT NULL,
) PRIMARY KEY(hashed_id, id, alias_id),
INTERLEAVE IN PARENT recording ON DELETE NO ACTION;
PostgreSQL
CREATE TABLE recording_alias (
id SERIAL, --PK
recording INTEGER NOT NULL, -- references recording.id
name VARCHAR NOT NULL,
locale TEXT,
edits_pending INTEGER NOT NULL DEFAULT 0 CHECK (edits_pending >=0),
last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
type INTEGER, -- references recording_alias_type.id
sort_name VARCHAR NOT NULL,
begin_date_year SMALLINT,
begin_date_month SMALLINT,
begin_date_day SMALLINT,
end_date_year SMALLINT,
end_date_month SMALLINT,
end_date_day SMALLINT,
primary_for_locale BOOLEAN NOT NULL DEFAULT false,
ended BOOLEAN NOT NULL DEFAULT FALSE
-- CHECK constraint skipped for brevity
);