Migre chaves principais

Esta página descreve como migrar chaves primárias das tabelas da base de dados de origem para bases de dados com o dialeto GoogleSQL do Spanner e bases de dados com o dialeto PostgreSQL. Antes de realizar os procedimentos na página, reveja a vista geral da migração da chave principal.

Antes de começar

  • Para receber as autorizações de que precisa para migrar chaves primárias para o Spanner, peça ao seu administrador para lhe conceder a função de IAM Administrador da base de dados do Cloud Spanner (roles/spanner.databaseAdmin) na instância.

Migre chaves sequenciais geradas automaticamente

Se estiver a migrar de uma base de dados que usa chaves monotónicas sequenciais, como AUTO_INCREMENT no MySQL, SERIAL no PostgreSQL ou o tipo IDENTITY padrão no SQL Server ou Oracle, considere a seguinte estratégia de migração de alto nível:

  1. No Spanner, replique a estrutura da tabela da base de dados de origem, usando uma chave primária de número inteiro.
  2. Para cada coluna no Spanner que contenha valores sequenciais, crie uma sequência e atribua a função GET_NEXT_SEQUENCE_VALUE ( GoogleSQL, PostgreSQL) como o valor predefinido para a coluna.
  3. Migre os dados existentes com chaves originais da base de dados de origem para o Spanner. Considere usar a ferramenta de migração do Spanner ou um modelo do Dataflow.
    1. Opcionalmente, pode estabelecer restrições de chave externa para quaisquer tabelas dependentes.
  4. Antes de inserir novos dados, ajuste a sequência do Spanner para ignorar o intervalo de valores-chave existentes.
  5. Inserir novos dados, permitindo que a sequência gere automaticamente chaves únicas.

Exemplo de fluxo de trabalho de migração

O código seguinte define a estrutura da tabela e a sequência relacionada no Spanner através de um objeto SEQUENCE e define o objeto como o valor principal predefinido da tabela de destino:

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)
);

A opção bit_reversed_positive indica que os valores gerados pela sequência são do tipo INT64, são superiores a zero e não são sequenciais.

À medida que migra as linhas existentes da base de dados de origem para o Spanner, as chaves primárias permanecem inalteradas.

Para novas inserções que não especifiquem uma chave primária, o Spanner obtém automaticamente um novo valor chamando a função GET_NEXT_SEQUENCE_VALUE(GoogleSQL ou PostgreSQL) .

Estes valores são distribuídos uniformemente no intervalo [1, 263] e podem ocorrer possíveis colisões com as chaves existentes. Para evitar esta situação, pode configurar a sequência através do ALTER_SEQUENCE (GoogleSQL ou PostgreSQL) para ignorar o intervalo de valores abrangidos pelas chaves existentes.

Suponha que a tabela singers foi migrada do PostgreSQL, onde a respetiva chave primária singer_id é do tipo SERIAL. O PostgreSQL seguinte mostra o LDD da base de dados de origem:

PostgreSQL

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

Os valores da chave principal estão a aumentar monotonicamente. Após a migração, pode obter o valor máximo da chave principal singer_id no Spanner. Use o seguinte código no Spanner:

GoogleSQL

SELECT MAX(SingerId) FROM Singers;

PostgreSQL

SELECT MAX(SingerId) FROM Singers;

Suponha que o valor devolvido é 20 000. Pode configurar a sequência do Spanner para ignorar o intervalo [1, 21000]. Os 1000 registos adicionais servem como um buffer para acomodar as gravações na base de dados de origem após a migração inicial. As novas chaves geradas no Spanner não entram em conflito com o intervalo de chaves primárias geradas na base de dados PostgreSQL de origem. Use o seguinte código no Spanner:

GoogleSQL

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

PostgreSQL

ALTER SEQUENCE SingerIdSequence SKIP RANGE 1 21000;

Use o Spanner e a sua base de dados de origem

Pode usar o conceito de intervalo de omissão para suportar cenários em que o Spanner ou a sua base de dados de origem gera chaves primárias, por exemplo, para ativar a replicação em qualquer direção para recuperação de desastres durante uma mudança de migração.

Para tal, ambas as bases de dados geram chaves primárias e os dados são sincronizados entre elas. Pode configurar cada base de dados para criar chaves primárias em intervalos de chaves não sobrepostos. Quando define um intervalo para a base de dados de origem, pode configurar a sequência do Spanner para ignorar esse intervalo.

Por exemplo, após a migração da aplicação de faixas de música, replique os dados do PostgreSQL para o Spanner para reduzir o tempo necessário para a transição.

Depois de atualizar e testar a aplicação no Spanner, pode deixar de usar a base de dados PostgreSQL de origem e usar o Spanner, tornando-o o sistema de registo para atualizações e novas chaves primárias. Quando o Spanner assume o controlo, pode inverter o fluxo de dados entre as bases de dados para a instância do PostgreSQL.

Suponha que a sua base de dados PostgreSQL de origem usa SERIAL chaves primárias, que são números inteiros com sinal de 32 bits. As chaves primárias do Spanner são números de 64 bits maiores. No PostgreSQL, altere a coluna de chave principal para ser uma coluna de 64 bits ou bigint. Use o seguinte código na base de dados PostgreSQL de origem:

PostgreSQL

ALTER TABLE Singers ALTER COLUMN SingerId TYPE bigint;

Pode definir uma restrição CHECK na tabela na base de dados PostgreSQL de origem para garantir que os valores da chave principal SingerId são sempre inferiores ou iguais a 231-1.

Use o seguinte código na base de dados PostgreSQL de origem:

PostgreSQL

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

No Spanner, podemos alterar a sequência para ignorar o intervalo [1, 231-1].

Use o seguinte código no 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;

A sua base de dados PostgreSQL de origem gera sempre chaves no espaço de números inteiros de 32 bits, enquanto as chaves do Spanner estão restritas ao espaço de números inteiros de 64 bits, que é maior do que todos os valores de números inteiros de 32 bits. Isto garante que ambas as bases de dados podem gerar independentemente chaves primárias que não entram em conflito.

Migre colunas de chaves UUID

As chaves UUIDv4 são efetivamente únicas, independentemente de onde são geradas. As chaves UUID geradas noutro local integram-se com as novas chaves UUID geradas no Spanner.

Considere a seguinte estratégia de alto nível para migrar chaves UUID para o Spanner:

  1. Defina as chaves UUID no Spanner com colunas de string com uma expressão predefinida. Use a função GENERATE_UUID()(GoogleSQL, PostgreSQL).
  2. Exporte os dados do sistema de origem, serializando as chaves UUID como strings.
  3. Importe as chaves primárias para o Spanner.
  4. Opcional: ative as chaves estrangeiras.

Segue-se um exemplo de fluxo de trabalho de migração:

No Spanner, defina uma coluna de chave primária UUID como um tipo STRING ou TEXT e atribua GENERATE_UUID() (GoogleSQL ou PostgreSQL) como o respetivo valor predefinido. Migre todos os dados da base de dados de origem para o Spanner. Após a migração, à medida que são inseridas novas linhas, o Spanner chama GENERATE_UUID() para gerar novos valores UUID para as chaves primárias. Por exemplo, a chave principal FanClubId recebe um valor UUIDv4 quando é inserida uma nova linha na tabela FanClubs. Use o seguinte código no 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');

Migre as suas próprias chaves principais

A sua aplicação pode depender da ordem da chave principal para determinar a antiguidade dos dados ou sequenciar os dados recém-criados. Para usar chaves sequenciais geradas externamente no Spanner, pode criar uma chave composta que combine um valor distribuído uniformemente, como um hash, como o primeiro componente, e a sua chave sequencial como o segundo componente. Desta forma, pode preservar os valores das chaves sequenciais sem criar pontos críticos em grande escala. Considere o seguinte fluxo de trabalho de migração:

Suponha que precisa de migrar uma tabela do MySQL students com uma chave primária AUTO_INCREMENT para o Spanner. Use o seguinte código na base de dados MySQL de origem:

MySQL

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

No Spanner, pode adicionar uma coluna gerada StudentIdHash criando um hash da coluna StudentId. Por exemplo:

StudentIdHash = FARM_FINGERPRINT(CAST(StudentId AS STRING))

Pode usar o seguinte código no 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)
);

Migre colunas de chaves sequenciais

Se o seu sistema de base de dados de origem gerar valores sequenciais para uma coluna de chave, pode usar uma sequência positiva invertida em bits (GoogleSQL, PostgreSQL) no seu esquema do Spanner para gerar valores que se distribuem uniformemente no espaço de números inteiros positivos de 64 bits. Para impedir que a sequência do Spanner gere um valor que se sobreponha a um valor migrado, pode definir um intervalo ignorado para a mesma.

Por exemplo, pode ignorar o intervalo de 1 a 4 294 967 296 (2^32) para as duas sequências seguintes, se souber que a base de dados de origem apenas gera números inteiros de 32 bits:

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;

Se estiver a usar IDENTITY colunas para gerar automaticamente valores inteiros para as colunas de chaves, pode definir skip ranges:

GoogleSQL

Para definir um intervalo de omissão, use o comando 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

Para definir um intervalo de omissão, use o comando 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;

Migre colunas de chaves invertidas em bits

Se já tiver invertido os bits dos seus valores-chave para evitar problemas de pontos críticos na base de dados de origem, também pode usar uma sequência positiva invertida por bits do Spanner (GoogleSQL, PostgreSQL) para continuar a gerar esses valores. Para evitar a geração de valores duplicados, pode configurar a sequência para iniciar a contagem a partir de um número personalizado.

Por exemplo, se tiver invertido os números de 1 a 1000 para gerar valores de chave primária, a sequência do Spanner pode iniciar o respetivo contador a partir de qualquer número superior a 10 000. Opcionalmente, pode escolher um número elevado para deixar um buffer para novas gravações que ocorram na base de dados de origem após a migração de dados. No exemplo seguinte, os contadores começam em 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;

Se estiver a usar IDENTITY colunas para gerar automaticamente valores inteiros para as colunas de chaves, pode definir um contador inicial:

GoogleSQL

Para definir um contador de início, use o comando 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

Para definir um contador de início, use o comando 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;

O que se segue?