遷移主鍵

本頁面說明如何將主鍵從來源資料庫資料表遷移至 Spanner GoogleSQL 方言資料庫和 PostgreSQL 方言資料庫。在頁面上執行程序前,請先詳閱「主鍵遷移總覽」。

事前準備

  • 如要取得將主鍵遷移至 Spanner 所需的權限,請要求管理員為您授予執行個體的 Cloud Spanner 資料庫管理員 (roles/spanner.databaseAdmin) IAM 角色。

遷移自動產生的連續金鑰

如果您要從使用序列單調鍵的資料庫進行遷移,例如 MySQL 中的 AUTO_INCREMENT、PostgreSQL 中的 SERIAL,或是 SQL Server 或 Oracle 中的標準 IDENTITY 類型,請考慮採用下列高層次遷移策略:

  1. 在 Spanner 中,使用整數主鍵複製來源資料庫的資料表結構。
  2. 針對 Spanner 中包含序列值的每個資料欄,建立序列並指派 GET_NEXT_SEQUENCE_VALUE ( GoogleSQLPostgreSQL) 函式做為資料欄的預設值。
  3. 將含有原始索引鍵的現有資料從來源資料庫遷移至 Spanner。建議您使用 Spanner 遷移工具 資料流範本
    1. 您可以選擇為任何依附資料表建立外鍵限制
  4. 插入新資料前,請調整 Spanner 序列,略過現有鍵值的範圍。
  5. 插入新資料,讓序列自動產生不重複的鍵。

遷移工作流程範例

以下程式碼使用 SEQUENCE 物件,在 Spanner 中定義資料表結構和相關序列,並將該物件設為目標資料表的預設主要值:

GoogleSQL

CREATE SEQUENCE singer_id_sequence OPTIONS (
     SequenceKind = 'bit_reversed_positive'
  );

CREATE TABLE Singers (
     SingerId INT64 DEFAULT
     (GET_NEXT_SEQUENCE_VALUE(SEQUENCE SingerIdSequence)),
     Name STRING(1024),
     Biography STRING(MAX),
  ) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
     AlbumId INT64,
     SingerId INT64,
     AlbumName STRING(1024),
     SongList STRING(MAX),
     CONSTRAINT FK_singer_album
     FOREIGN KEY (SingerId)
       REFERENCES Singers (SingerId)
  ) PRIMARY KEY (AlbumId);

PostgreSQL

CREATE SEQUENCE SingerIdSequence BIT_REVERSED_POSITIVE;

CREATE TABLE Singers (
  SingerId BIGINT DEFAULT nextval('SingerIdSequence') PRIMARY KEY,
  Name VARCHAR(1024) NOT NULL,
  Biography TEXT
);

CREATE TABLE Albums (
  AlbumId BIGINT PRIMARY KEY,
  SingerId BIGINT,
  AlbumName VARCHAR(1024),
  SongList TEXT,
  CONSTRAINT FK_singer_album FOREIGN KEY (SingerId) REFERENCES Singers (SingerId)
);

bit_reversed_positive 選項表示序列產生的值為 INT64 類型、大於零,且不是連續的。

當您將現有資料列從來源資料庫遷移至 Spanner 時,主鍵會保持不變。

如果新插入的資料未指定主鍵,Spanner 會透過呼叫 GET_NEXT_SEQUENCE_VALUE(GoogleSQLPostgreSQL) 函式,自動擷取新值。

這些值會平均分佈在 [1, 263] 範圍內,且可能與現有鍵發生衝突。為避免這種情況,您可以使用 ALTER_SEQUENCE (GoogleSQLPostgreSQL) 設定序列,跳過現有鍵涵蓋的值範圍。

假設 singers 資料表是從 PostgreSQL 遷移而來,且其主鍵 singer_idSERIAL 類型。以下 PostgreSQL 會顯示來源資料庫 DDL:

PostgreSQL

CREATE TABLE Singers (
SingerId SERIAL PRIMARY KEY,
Name varchar(1024),
Biography varchar
);

主鍵值是單調遞增的。遷移完成後,您可以在 Spanner 上擷取主鍵 singer_id 的最大值。在 Spanner 中使用下列程式碼:

GoogleSQL

SELECT MAX(SingerId) FROM Singers;

PostgreSQL

SELECT MAX(SingerId) FROM Singers;

假設傳回值為 20,000。您可以設定 Spanner 序列,略過範圍 [1, 21000]。額外的 1,000 則可做為緩衝區,以便在初始遷移作業完成後,寫入來源資料庫。在 Spanner 中產生的鍵不會與來源 PostgreSQL 資料庫中產生的主鍵範圍衝突。在 Spanner 中使用下列程式碼:

GoogleSQL

ALTER SEQUENCE SingerIdSequence SET OPTIONS (
skip_range_min = 1,
skip_range_max = 21000
);

PostgreSQL

ALTER SEQUENCE SingerIdSequence SKIP RANGE 1 21000;

使用 Spanner 和來源資料庫

您可以使用略過範圍概念,支援 Spanner 或來源資料庫產生主鍵的情況,例如在遷移切換期間,為災難復原目的啟用任一方向的複製作業。

為支援這項功能,兩個資料庫都會產生主鍵,並同步處理兩者之間的資料。您可以設定每個資料庫,在不重疊的鍵範圍內建立主鍵。為來源資料庫定義範圍時,您可以設定 Spanner 序列略過該範圍。

舉例來說,在音樂曲目應用程式遷移完成後,請將資料從 PostgreSQL 複製到 Spanner,以縮短切換所需的時間。

在 Spanner 上更新及測試應用程式後,您可以停止使用來源 PostgreSQL 資料庫,改用 Spanner,讓 Spanner 成為更新和新主鍵的記錄系統。當 Spanner 接手後,您可以將資料流量從資料庫反向流入 PostgreSQL 執行個體。

假設來源 PostgreSQL 資料庫使用 SERIAL 主鍵,也就是 32 位元帶號整數。Spanner 主鍵是較大的 64 位元數字。在 PostgreSQL 中,將主鍵資料欄變更為 64 位元資料欄或 bigint。在來源 PostgreSQL 資料庫上使用以下程式碼:

PostgreSQL

ALTER TABLE Singers ALTER COLUMN SingerId TYPE bigint;

您可以為來源 PostgreSQL 資料庫中的資料表設定 CHECK 限制,確保 SingerId 主鍵的值一律小於或等於 231-1

在來源 PostgreSQL 資料庫中使用以下程式碼:

PostgreSQL

ALTER TABLE Singers ADD CHECK (SingerId <= 2147483647);

在 Spanner 中,我們可以變更序列,略過 [1, 231-1] 範圍。

在 Spanner 中使用下列程式碼:

GoogleSQL

ALTER SEQUENCE SingerIdSequence SET OPTIONS (
skip_range_min = 1,
skip_range_max = 2147483647 -- 231-1
);

PostgreSQL

ALTER SEQUENCE SingerIdSequence SKIP RANGE 1 2147483648;

來源 PostgreSQL 資料庫一律會在 32 位元整數空間中產生索引鍵,而 Spanner 索引鍵則受限於 64 位元整數空間,大於所有 32 位元整數值。這可確保兩個資料庫都能獨立產生不會衝突的主鍵。

遷移 UUID 鍵資料欄

無論 UUIDv4 金鑰是在何處產生,都會是獨一無二的。在其他地方產生的 UUID 鍵會與 Spanner 中產生的新 UUID 鍵整合。

請考慮採用下列高層策略,將 UUID 鍵遷移至 Spanner:

  1. 使用含有預設運算式的字串資料欄,在 Spanner 中定義 UUID 鍵。使用 GENERATE_UUID() 函式 (GoogleSQLPostgreSQL)。
  2. 從來源系統匯出資料,並將 UUID 鍵序列化為字串。
  3. 將主鍵匯入 Spanner。
  4. 選用:啟用外鍵。

以下是遷移工作流程範例:

在 Spanner 中,將 UUID 主鍵欄定義為 STRINGTEXT 類型,並將 GENERATE_UUID() (GoogleSQLPostgreSQL) 指派為其預設值。將所有資料從來源資料庫遷移至 Spanner。遷移完成後,當新的資料列插入時,Spanner 會呼叫 GENERATE_UUID(),為主鍵產生新的 UUID 值。舉例來說,當資料表 FanClubs 中插入新資料列時,主鍵 FanClubId 會取得 UUIDv4 值。在 Spanner 中使用以下程式碼:

GoogleSQL

CREATE TABLE Fanclubs (
FanClubId STRING(36) DEFAULT (GENERATE_UUID()),
ClubName STRING(1024),
) PRIMARY KEY (FanClubId);

INSERT INTO FanClubs (ClubName) VALUES ("SwiftFanClub");

PostgreSQL

CREATE TABLE FanClubs (
  FanClubId TEXT DEFAULT spanner.generate_uuid() PRIMARY KEY,
  ClubName VARCHAR(1024)
);

INSERT INTO FanClubs (ClubName) VALUES ('SwiftFanClub');

遷移自己的主鍵

應用程式可能會依據主鍵順序判斷資料的最新狀態,或為新建立的資料排序。如要在 Spanner 中使用外部產生的順序鍵,您可以建立複合鍵,將均勻分布的值 (例如雜湊值) 做為第一個元件,並將順序鍵做為第二個元件。這樣一來,您就能保留順序鍵值,而不會大規模建立熱點。請考慮下列遷移工作流程:

假設您需要將具有 AUTO_INCREMENT 主鍵的 MySQL 資料表 students 遷移至 Spanner。在來源 MySQL 資料庫中使用以下程式碼:

MySQL

CREATE TABLE Students (
StudentId INT NOT NULL AUTO_INCREMENT,
Info VARCHAR(2048),
PRIMARY KEY (StudentId)
);

在 Spanner 中,您可以建立 StudentId 欄的雜湊,藉此新增產生的資料欄 StudentIdHash。例如:

StudentIdHash = FARM_FINGERPRINT(CAST(StudentId AS STRING))

您可以在 Spanner 中使用下列程式碼:

GoogleSQL

CREATE TABLE student (
  StudentIdHash INT64 AS (FARM_FINGERPRINT(cast(StudentId as string))) STORED,
  StudentId INT64 NOT NULL,
  Info STRING(2048),
) PRIMARY KEY(StudentIdHash, StudentId);

PostgreSQL

CREATE TABLE Student (
  StudentIdHash bigint GENERATED ALWAYS AS
  (FARM_FINGERPRINT(cast(StudentId AS varchar))) STORED,
  StudentId bigint NOT NULL,
  Info varchar(2048),
  PRIMARY KEY (StudentIdHash, StudentId)
);

遷移序列索引鍵欄

如果來源資料庫系統會為關鍵欄產生序列值,您可以在 Spanner 結構定義中使用位元反轉的正序序列 (GoogleSQLPostgreSQL),產生在正 64 位元整數數字空間中平均分配的值。為避免 Spanner 序列產生的值與遷移的值重疊,您可以為該序列定義略過的範圍。

舉例來說,如果您知道來源資料庫只會產生 32 位元整數,則可以略過下列兩個序列的 1 到 4,294,967,296 (2^32) 範圍:

GoogleSQL

CREATE SEQUENCE MyFirstSequence OPTIONS (
  sequence_kind = "bit_reversed_positive",
  skip_range_min = 1,
  skip_range_max = 4294967296
);

ALTER SEQUENCE MySecondSequence SET OPTIONS (
  skip_range_min = 1,
  skip_range_max = 4294967296
);

PostgreSQL

CREATE SEQUENCE MyFirstSequence BIT_REVERSED_POSITIVE
  SKIP RANGE 1 4294967296;

ALTER SEQUENCE MySecondSequence SKIP RANGE 1 4294967296;

如果您使用 IDENTITY 資料欄自動產生主要欄的整數值,可以設定略過範圍:

GoogleSQL

如要設定略過範圍,請使用 GENERATED BY DEFAULT AS IDENTITY 指令:

ALTER DATABASE db SET OPTIONS (
  default_sequence_kind = 'bit_reversed_positive',
);

CREATE TABLE MyFirstTable (
  Id INT64 GENERATED BY DEFAULT AS IDENTITY (SKIP RANGE 1, 4294967296),
  Name STRING(MAX),
) PRIMARY KEY (Id);

ALTER TABLE MyFirstTable ALTER COLUMN Id ALTER IDENTITY SET SKIP RANGE 1, 4294967296;

PostgreSQL

如要設定略過範圍,請使用 GENERATED BY DEFAULT AS IDENTITY 指令:

ALTER DATABASE db
    SET spanner.default_sequence_kind = 'bit_reversed_positive';

CREATE TABLE MyFirstTable (
  Id bigint GENERATED BY DEFAULT AS IDENTITY (SKIP RANGE 1 4294967296),
  Name text,
  PRIMARY KEY (Id)
);

ALTER TABLE MyFirstTable ALTER COLUMN Id SET SKIP RANGE 1 4294967296;

遷移位元反轉的索引鍵欄

如果您已將索引鍵值反向位元,以避免來源資料庫出現熱點問題,也可以使用 Spanner 反向位元正序序列 (GoogleSQLPostgreSQL) 繼續產生這類值。為避免產生重複值,您可以將序列設為從自訂編號開始計數。

舉例來說,如果您將 1 到 1000 的數字倒轉,產生主鍵值,Spanner 序列可以從任何大於 10,000 的數字開始計數。您可以選擇較高的數字,為資料遷移後在來源資料庫中發生的新寫入作業保留緩衝區。在下列範例中,計數器會從 11,000 開始:

GoogleSQL

CREATE SEQUENCE MyFirstSequence OPTIONS (
  sequence_kind = "bit_reversed_positive",
  start_with_counter = 11000
);

ALTER SEQUENCE MySecondSequence SET OPTIONS (
  start_with_counter = 11000
);

PostgreSQL

CREATE SEQUENCE MyFirstSequence BIT_REVERSED_POSITIVE
  START COUNTER 11000;

ALTER SEQUENCE MySecondSequence RESTART COUNTER 11000;

如果您使用 IDENTITY自動產生主要欄的整數值,可以設定起始計數器:

GoogleSQL

如要設定起始計數器,請使用 GENERATED BY DEFAULT AS IDENTITY 指令:

ALTER DATABASE db SET OPTIONS (
  default_sequence_kind = 'bit_reversed_positive',
);

CREATE TABLE MyFirstTable (
  Id INT64 GENERATED BY DEFAULT AS IDENTITY (START COUNTER WITH 11000),
  Name STRING(MAX),
) PRIMARY KEY (Id);

ALTER TABLE MyFirstTable ALTER COLUMN Id ALTER IDENTITY RESTART COUNTER WITH 11000;

PostgreSQL

如要設定起始計數器,請使用 GENERATED BY DEFAULT AS IDENTITY 指令:

ALTER DATABASE db
    SET spanner.default_sequence_kind = 'bit_reversed_positive';

CREATE TABLE MyFirstTable (
  Id bigint GENERATED BY DEFAULT AS IDENTITY (START COUNTER WITH 11000),
  Name text,
  PRIMARY KEY (Id)
);

ALTER TABLE MyFirstTable ALTER COLUMN Id RESTART COUNTER WITH 11000;

後續步驟