Migrar chaves primárias

Nesta página, descrevemos como migrar chaves primárias das tabelas do banco de dados de origem para bancos de dados do dialeto GoogleSQL e do dialeto PostgreSQL do Spanner. Antes de realizar os procedimentos na página, revise a visão geral da migração de chaves primárias.

Antes de começar

Migrar chaves sequenciais geradas automaticamente

Se você estiver migrando de um banco 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 do banco de dados de origem usando uma chave primária inteira.
  2. Para cada coluna no Spanner que contém valores sequenciais, crie uma sequência e atribua a GET_NEXT_SEQUENCE_VALUE ( GoogleSQL, PostgreSQL) função como o valor padrão da coluna.
  3. Migre os dados atuais com chaves originais do banco de dados de origem para o Spanner. Considere usar a ferramenta de migração do Spanner ou um modelo doDataflow.
    1. Opcionalmente, é possível estabelecer restrições de chave estrangeira para tabelas dependentes .
  4. Antes de inserir novos dados, ajuste a sequência do Spanner para pular o intervalo de valores de chave atuais.
  5. Insira novos dados, permitindo que a sequência gere chaves exclusivas automaticamente.

Exemplo de fluxo de trabalho de migração

O código a seguir define a estrutura da tabela e a sequência relacionada no Spanner usando um SEQUENCE objeto e define o objeto como o valor primário padrão da tabela de destino tabela:

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 maiores que zero e não são sequenciais.

À medida que você migra linhas atuais do banco de dados de origem para o Spanner, as chaves primárias permanecem inalteradas.

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

Esses valores são distribuídos uniformemente no intervalo [1, 263] e pode haver colisões com as chaves atuais. Para evitar isso, é possível configurar a sequência usando ALTER_SEQUENCE (GoogleSQL ou PostgreSQL) para pular o intervalo de valores cobertos pelas chaves atuais.

Suponha que a tabela singers tenha sido migrada do PostgreSQL, em que a chave primária singer_id é do tipo SERIAL. O PostgreSQL a seguir mostra a DDL do banco de dados de origem:

PostgreSQL

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

Os valores da chave primária aumentam monotonicamente. Após a migração, é possível recuperar o valor máximo da chave primária singer_id no Spanner. Use o código a seguir no Spanner:

GoogleSQL

SELECT MAX(SingerId) FROM Singers;

PostgreSQL

SELECT MAX(SingerId) FROM Singers;

Suponha que o valor retornado seja 20.000. É possível configurar a sequência do Spanner para pular o intervalo [1, 21000]. Os 1.000 adicionais servem como um buffer para acomodar gravações no banco 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 no banco de dados PostgreSQL de origem. Use o código a seguir no Spanner:

GoogleSQL

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

PostgreSQL

ALTER SEQUENCE SingerIdSequence SKIP RANGE 1 21000;

Usar o Spanner e o banco de dados de origem

É possível usar o conceito de intervalo de pular para oferecer suporte a cenários em que o Spanner ou o banco 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 transição de migração.

Para oferecer suporte a isso, os dois bancos de dados geram chaves primárias, e os dados são sincronizados entre eles. É possível configurar cada banco de dados para criar chaves primárias em intervalos de chaves não sobrepostos. Ao definir um intervalo para o banco de dados de origem, é possível configurar a sequência do Spanner para pular esse intervalo.

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

Depois de atualizar e testar o aplicativo no Spanner, é possível parar de usar o banco de dados PostgreSQL de origem e usar o Spanner, tornando-o o sistema de registro para atualizações e novas chaves primárias. Quando o Spanner assumir o controle, será possível inverter o fluxo de dados entre os bancos de dados na instância do PostgreSQL.

Suponha que o banco de dados PostgreSQL de origem use chaves primárias SERIAL, que são números inteiros assinados de 32 bits. As chaves primárias do Spanner são números de 64 bits maiores. No PostgreSQL, altere a coluna da chave primária para ser uma coluna de 64 bits ou bigint. Use o código a seguir no banco de dados PostgreSQL de origem:

PostgreSQL

ALTER TABLE Singers ALTER COLUMN SingerId TYPE bigint;

É possível definir uma resteração CHECK na tabela no banco de dados PostgreSQL de origem para garantir que os valores da chave primária SingerId sejam sempre menores ou iguais a 231-1.

Use o código a seguir no banco de dados PostgreSQL de origem:

PostgreSQL

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

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

Use o código a seguir 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;

O banco de dados PostgreSQL de origem sempre gera chaves no espaço de números inteiros de 32 bits, enquanto as chaves do Spanner são restritas ao espaço de números inteiros de 64 bits, maior que todos os valores de números inteiros de 32 bits. Isso garante que os dois bancos de dados possam gerar chaves primárias independentemente que não entrem em conflito.

Migrar colunas de chave UUID

As chaves UUIDv4 são efetivamente exclusivas, independentemente de onde são geradas. As chaves UUID geradas em outro lugar são integradas a 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 usando colunas de string com uma expressão padrão. 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.

Confira 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 valor padrão. Migre todos os dados do banco de dados de origem para o Spanner. Após a migração, à medida que novas linhas são inseridas, o Spanner chama GENERATE_UUID() para gerar novos valores UUID para as chaves primárias. Por exemplo, a chave primária FanClubId recebe um valor UUIDv4 quando uma nova linha é inserida na tabela FanClubs. Use o código a seguir 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');

Migrar suas próprias chaves primárias

Seu aplicativo pode depender da ordem da chave primária para determinar a data dos dados ou para sequenciar dados recém-criados. Para usar chaves sequenciais geradas externamente no Spanner, é possível criar uma chave composta que combina um valor distribuído uniformemente, como um hash, como o primeiro componente e a chave sequencial como o segundo componente. Dessa forma, é possível preservar os valores de chave sequenciais sem criar pontos de acesso em escala. Considere o seguinte fluxo de trabalho de migração:

Suponha que você precise migrar uma tabela students do MySQL com uma chave primária AUTO_INCREMENT para o Spanner. Use o código a seguir no banco de dados MySQL de origem:

MySQL

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

No Spanner, é possível adicionar uma coluna gerada StudentIdHash por criar um hash da coluna StudentId. Exemplo:

StudentIdHash = FARM_FINGERPRINT(CAST(StudentId AS STRING))

É possível usar o código a seguir 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)
);

Migrar colunas de chave sequenciais

Se o sistema de banco de dados de origem gerar valores sequenciais para uma coluna de chave, é possível usar uma sequência positiva invertida por bits (GoogleSQL, PostgreSQL) no esquema do Spanner para gerar valores que são distribuídos uniformemente no espaço de números inteiros positivos de 64 bits. Para evitar que a sequência do Spanner gere um valor que se sobreponha a um valor migrado, é possível definir um intervalo ignorado para ele.

Por exemplo, é possível pular o intervalo de 1 a 4.294.967.296 (2^32) para as duas sequências a seguir, se você souber que o banco de dados de origem só 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 você estiver usando IDENTITY colunas para gerar automaticamente valores inteiros para as colunas de chave, é possível definir intervalos de pular:

GoogleSQL

Para definir um intervalo de pular, use o GENERATED BY DEFAULT AS IDENTITY comando:

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 pular, use o GENERATED BY DEFAULT AS IDENTITY comando:

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;

Migrar colunas de chave invertidas por bits

Se você já tiver invertido os valores de chave por bits para evitar problemas de ponto de acesso no banco de dados de origem, também será possível usar uma sequência positiva invertida por bits do Spanner (GoogleSQL, PostgreSQL) para continuar gerando esses valores. Para evitar a geração de valores duplicados, é possível configurar a sequência para iniciar o contador de um número personalizado.

Por exemplo, se você reverteu números de 1 a 1.000 para gerar valores de chave primária, a sequência do Spanner poderá iniciar o contador de qualquer número maior que 10.000. Opcionalmente, é possível escolher um número alto para deixar um buffer para novas gravações que ocorrem no banco de dados de origem após a migração de dados. No exemplo a seguir, 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 você estiver usando IDENTITY colunas para gerar automaticamente valores inteiros para as colunas de chave, é possível definir um contador inicial:

GoogleSQL

Para definir um contador inicial, use o GENERATED BY DEFAULT AS IDENTITY comando:

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 inicial, use o GENERATED BY DEFAULT AS IDENTITY comando:

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;

A seguir