迁移主键

本文档提供了从哪个位置迁移主键的说明 将源数据库表复制到 Spanner。您必须熟悉 此处提供的信息 主键迁移概览

准备工作

  • 如需获得将主键迁移到 Spanner 所需的权限,请让您的管理员为您授予实例的 Cloud Spanner Database Admin (roles/spanner.databaseAdmin) IAM 角色。

迁移自动生成的序列键

如果要从使用顺序单调键的数据库进行迁移, 例如 AUTO_INCREMENT 在 MySQL 中,SERIAL 或者 SQL Server 或 Oracle 中的标准 IDENTITY 类型。 请考虑采用以下总体迁移策略:

  1. 在 Spanner 中,从 您的源数据库(使用整数主键)。
  2. 对于 Spanner 中包含顺序值的每一列, 创建一个序列并分配 GET_NEXT_SEQUENCE_VALUEGoogleSQLPostgreSQL) 函数作为列的默认值。
  3. 将具有原始键的现有数据从源数据库迁移到 Spanner。您可以考虑使用 Spanner 迁移工具Dataflow 模板
  4. 您可以视需要 外键约束 依赖表
  5. 在插入新数据之前,请调整 Spanner 序列,以跳过现有键值的范围。
  6. 插入新数据,使序列能够自动生成唯一键。

迁移工作流示例

以下代码使用 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 会通过调用 GET_NEXT_SEQUENCE_VALUE()GoogleSQLPostgreSQL)函数自动检索新值。

这些值在 [1, 263] 范围内均匀分布, 可能会与现有密钥发生冲突。为防止出现这种情况,您可以使用 ALTER_SEQUENCEGoogleSQLPostgreSQL)配置序列,以跳过现有键涵盖的值范围。

假设 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 序列以跳过该范围。

例如,在迁移音乐曲目应用后,请复制 将数据从 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 键导入 Spanner:

  1. 在 Spanner 中,使用带有默认表达式的字符串列定义 UUID 键。使用 GENERATE_UUID() 函数(GoogleSQLPostgreSQL)。
  2. 从源系统导出数据,将 UUID 键序列化为字符串。
  3. 将主键导入 Spanner。
  4. 可选:启用外键。

下面是一个迁移工作流程示例:

在 Spanner 中,将 UUID 主键列定义为 STRING,或 TEXT 类型,并将 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 中使用外部生成的顺序键,您可以创建一个复合键,将均匀分布的值(例如哈希值)作为第一个组件,将顺序键作为第二个组件。这样,您就可以保留顺序键值,而不会大规模创建热点。请考虑以下迁移工作流:

假设您需要迁移一个 MySQL 表 students,该表为 分配给 Spanner 的 AUTO_INCREMENT 主键。 在源 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)
);

后续步骤