遷移主鍵

本頁面說明如何將來源資料庫資料表的主鍵遷移至 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 遷移工具 Dataflow 範本
    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 接管後,您可以將資料庫之間的資料流向反轉至 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;

後續步驟