Esegui la migrazione delle chiavi primarie

Questa pagina descrive come eseguire la migrazione delle chiavi primarie dalle tabelle del database di origine ai database con dialetto GoogleSQL e PostgreSQL di Spanner. Prima di eseguire le procedure descritte nella pagina, consulta la panoramica della migrazione delle chiavi primarie.

Prima di iniziare

Eseguire la migrazione delle chiavi sequenziali generate automaticamente

Se esegui la migrazione da un database che utilizza chiavi sequenziali monotoniche, come AUTO_INCREMENT in MySQL, SERIAL in PostgreSQL o il tipo IDENTITY standard in SQL Server o Oracle, valuta la seguente strategia di migrazione di alto livello:

  1. In Spanner, replica la struttura della tabella dal database di origine utilizzando una chiave primaria intera.
  2. Per ogni colonna in Spanner che contiene valori sequenziali, crea una sequenza e assegna la GET_NEXT_SEQUENCE_VALUE ( GoogleSQL, PostgreSQL) funzione come valore predefinito per la colonna.
  3. Esegui la migrazione dei dati esistenti con le chiavi originali dal database di origine a Spanner. Valuta la possibilità di utilizzare lo strumento di migrazione Spanner tool o un modello Dataflow template.
    1. (Facoltativo) Puoi stabilire vincoli di chiave esterna per le tabelle dipendenti.
  4. Prima di inserire nuovi dati, regola la sequenza di Spanner in modo da saltare l'intervallo di valori chiave esistenti.
  5. Inserisci nuovi dati, consentendo alla sequenza di generare automaticamente chiavi univoche.

Flusso di lavoro di migrazione di esempio

Il seguente codice definisce la struttura della tabella e la sequenza correlata in Spanner utilizzando un SEQUENCE oggetto e imposta l'oggetto come valore primario predefinito della tabella di destinazione:

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

L'opzione bit_reversed_positive indica che i valori generati dalla sequenza sono di tipo INT64, sono maggiori di zero e non sono sequenziali.

Quando esegui la migrazione delle righe esistenti dal database di origine a Spanner, le chiavi primarie rimangono invariate.

Per i nuovi inserimenti che non specificano una chiave primaria, Spanner recupera automaticamente un nuovo valore chiamando la funzione GET_NEXT_SEQUENCE_VALUE(GoogleSQL o PostgreSQL) .

Questi valori sono distribuiti uniformemente nell'intervallo [1, 263] e potrebbero verificarsi possibili conflitti con le chiavi esistenti. Per evitare questo problema, puoi configurare la sequenza utilizzando ALTER_SEQUENCE (GoogleSQL o PostgreSQL) per saltare l'intervallo di valori coperti dalle chiavi esistenti.

Supponiamo che la tabella singers sia stata migrata da PostgreSQL, dove la chiave primaria singer_id è di tipo SERIAL. Il seguente PostgreSQL mostra il DDL del database di origine:

PostgreSQL

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

I valori della chiave primaria aumentano in modo monotono. Dopo la migrazione, puoi recuperare il valore massimo della chiave primaria singer_id su Spanner. Utilizza il seguente codice in Spanner:

GoogleSQL

SELECT MAX(SingerId) FROM Singers;

PostgreSQL

SELECT MAX(SingerId) FROM Singers;

Supponiamo che il valore restituito sia 20.000. Puoi configurare la sequenza di Spanner in modo da saltare l'intervallo [1, 21000]. I 1000 aggiuntivi fungono da buffer per ospitare le scritture nel database di origine dopo la migrazione iniziale. Le nuove chiavi generate in Spanner non sono in conflitto con l'intervallo di chiavi primarie generate nel database PostgreSQL di origine. Utilizza il seguente codice in Spanner:

GoogleSQL

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

PostgreSQL

ALTER SEQUENCE SingerIdSequence SKIP RANGE 1 21000;

Utilizzare Spanner e il database di origine

Puoi utilizzare il concetto di intervallo di salto per supportare scenari in cui Spanner o il database di origine generano chiavi primarie, ad esempio per abilitare la replica in entrambe le direzioni per ripristino di emergenza durante un cutover di migrazione.

Per supportare questa funzionalità, entrambi i database generano chiavi primarie e i dati vengono sincronizzati tra loro. Puoi configurare ogni database per creare chiavi primarie in intervalli di chiavi non sovrapposti. Quando definisci un intervallo per il database di origine, puoi configurare la sequenza di Spanner in modo da saltare l'intervallo.

Ad esempio, dopo la migrazione dell'applicazione di brani musicali, replica i dati da PostgreSQL a Spanner per ridurre il tempo necessario per il cutover.

Dopo aver aggiornato e testato l'applicazione su Spanner, puoi interrompere l'utilizzo del database PostgreSQL di origine e utilizzare Spanner, rendendolo il sistema di record per gli aggiornamenti e le nuove chiavi primarie. Quando Spanner prende il controllo, puoi invertire il flusso di dati tra i database nell'istanza PostgreSQL.

Supponiamo che il database PostgreSQL di origine utilizzi chiavi primarie SERIAL, che sono numeri interi con segno a 32 bit. Le chiavi primarie di Spanner sono numeri a 64 bit più grandi. In PostgreSQL, modifica la colonna della chiave primaria in modo che sia una colonna a 64 bit o bigint. Utilizza il seguente codice nel database PostgreSQL di origine:

PostgreSQL

ALTER TABLE Singers ALTER COLUMN SingerId TYPE bigint;

Puoi impostare un vincolo CHECK sulla tabella nel database PostgreSQL di origine per assicurarti che i valori della chiave primaria SingerId siano sempre minori o uguali a 231-1.

Utilizza il seguente codice nel database PostgreSQL di origine:

PostgreSQL

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

In Spanner, possiamo modificare la sequenza in modo da saltare l'intervallo [1, 231-1] range.

Utilizza il seguente codice in 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;

Il database PostgreSQL di origine genera sempre chiavi nello spazio intero a 32 bit, mentre le chiavi di Spanner sono limitate allo spazio intero a 64 bit, maggiore di tutti i valori interi a 32 bit. In questo modo, entrambi i database possono generare in modo indipendente chiavi primarie che non sono in conflitto.

Eseguire la migrazione delle colonne delle chiavi UUID

Le chiavi UUIDv4 sono effettivamente univoche indipendentemente da dove vengono generate. Le chiavi UUID generate altrove si integrano con le nuove chiavi UUID generate in Spanner.

Valuta la seguente strategia di alto livello per eseguire la migrazione delle chiavi UUID a Spanner:

  1. Definisci le chiavi UUID in Spanner utilizzando colonne stringa con un'espressione predefinita. Utilizza la GENERATE_UUID() funzione (GoogleSQL, PostgreSQL).
  2. Esporta i dati dal sistema di origine, serializzando le chiavi UUID come stringhe.
  3. Importa le chiavi primarie in Spanner.
  4. (Facoltativo) Abilita le chiavi esterne.

Di seguito è riportato un flusso di lavoro di migrazione di esempio:

In Spanner, definisci una colonna della chiave primaria UUID come tipo STRING o TEXT e assegna GENERATE_UUID() (GoogleSQL o PostgreSQL) come valore predefinito. Esegui la migrazione di tutti i dati dal database di origine a Spanner. Dopo la migrazione, quando vengono inserite nuove righe, Spanner chiama GENERATE_UUID() per generare nuovi valori UUID per le chiavi primarie. Ad esempio, la chiave primaria FanClubId riceve un valore UUIDv4 quando viene inserita una nuova riga nella tabella FanClubs. Utilizza il seguente codice in 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');

Eseguire la migrazione delle proprie chiavi primarie

La tua applicazione potrebbe fare affidamento sull'ordine chiave primaria per determinare la data di creazione dei dati o per sequenziare i dati appena creati. Per utilizzare chiavi sequenziali generate esternamente in Spanner, puoi creare una chiave composta che combini un valore distribuito uniformemente, ad esempio un hash, come primo componente e la chiave sequenziale come secondo componente. In questo modo, puoi conservare i valori delle chiavi sequenziali senza creare hotspot su larga scala. Valuta il seguente flusso di lavoro di migrazione:

Supponiamo che tu debba eseguire la migrazione di una tabella MySQL students con una chiave primaria AUTO_INCREMENT a Spanner. Utilizza il seguente codice nel database MySQL di origine:

MySQL

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

In Spanner, puoi aggiungere una colonna generata StudentIdHash by creando un hash della colonna StudentId. Ad esempio:

StudentIdHash = FARM_FINGERPRINT(CAST(StudentId AS STRING))

Puoi utilizzare il seguente codice in 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)
);

Eseguire la migrazione delle colonne delle chiavi sequenziali

Se il sistema di database di origine genera valori sequenziali per una colonna chiave, puoi utilizzare una sequenza positiva con inversione di bit (GoogleSQL, PostgreSQL) nello schema di Spanner per generare valori che si distribuiscono uniformemente nello spazio numerico intero positivo a 64 bit. Per impedire alla sequenza di Spanner di generare un valore che si sovrappone a un valore migrato, puoi definire un intervallo saltato.

Ad esempio, puoi saltare l'intervallo da 1 a 4.294.967.296 (2^32) per le due sequenze seguenti, se sai che il database di origine genera solo numeri interi a 32 bit:

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 utilizzi IDENTITY colonne per generare automaticamente valori interi per le colonne delle chiavi, puoi impostare gli intervalli di salto:

GoogleSQL

Per impostare un intervallo di salto, utilizza il 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

Per impostare un intervallo di salto, utilizza il 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;

Eseguire la migrazione delle colonne delle chiavi con inversione di bit

Se hai già invertito i valori delle chiavi per evitare problemi di hotspot nel database di origine, puoi anche utilizzare una sequenza positiva con inversione di bit di Spanner (GoogleSQL, PostgreSQL) per continuare a generare questi valori. Per evitare di generare valori duplicati, puoi configurare la sequenza in modo che inizi il contatore da un numero personalizzato.

Ad esempio, se hai invertito i numeri da 1 a 1000 per generare valori di chiave primaria, la sequenza di Spanner può iniziare il contatore da un numero maggiore di 10.000. (Facoltativo) Puoi scegliere un numero elevato per lasciare un buffer per le nuove scritture che si verificano nel database di origine dopo la migrazione dei dati. Nell'esempio seguente, i contatori iniziano da 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 utilizzi IDENTITY colonne per generare automaticamente valori interi per le colonne delle chiavi, puoi impostare un contatore iniziale:

GoogleSQL

Per impostare un contatore iniziale, utilizza il 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

Per impostare un contatore iniziale, utilizza il 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;

Passaggi successivi