העברת מפתחות ראשיים

בדף הזה מוסבר איך להעביר מפתחות ראשיים מטבלאות במסד הנתונים של המקור למסדי נתונים של Spanner עם ניב GoogleSQL ולמסדי נתונים עם ניב PostgreSQL. לפני שמבצעים את הפעולות שמתוארות בדף, כדאי לעיין בסקירה הכללית של העברת מפתח ראשי.

לפני שמתחילים

  • כדי לקבל את ההרשאות שנדרשות להעברת מפתחות ראשיים ל-Spanner, צריך לבקש מהאדמין להקצות לכם ב-IAM את התפקיד אדמין של מסד נתונים ב-Cloud Spanner (roles/spanner.databaseAdmin) במופע.

העברת מפתחות רציפים שנוצרו אוטומטית

אם אתם מעבירים נתונים ממסד נתונים שמשתמש במפתחות מונוטוניים רציפים, כמו AUTO_INCREMENT ב-MySQL,‏ SERIAL ב-PostgreSQL או הסוג IDENTITY הרגיל בשרת SQL או ב-Oracle, כדאי לשקול את אסטרטגיית ההעברה הבאה ברמה גבוהה:

  1. ב-Spanner, משכפלים את מבנה הטבלה ממסד הנתונים של המקור באמצעות מפתח ראשי מסוג מספר שלם.
  2. לכל עמודה ב-Spanner שמכילה ערכים עוקבים, יוצרים רצף ומקצים את הפונקציה GET_NEXT_SEQUENCE_VALUE ( GoogleSQL,‏ PostgreSQL) כערך ברירת המחדל של העמודה.
  3. העברת נתונים קיימים עם מפתחות מקוריים ממסד הנתונים של המקור אל Spanner. אפשר להשתמש בכלי להעברת נתונים ל-Spanner או ב תבנית Dataflow.
    1. אפשר גם להגדיר אילוצי מפתח זר לכל הטבלאות התלויות.
  4. לפני שמוסיפים נתונים חדשים, צריך לשנות את רצף Spanner כדי לדלג על טווח ערכי המפתח הקיימים.
  5. להוסיף נתונים חדשים, כדי שהרצף ייצור מפתחות ייחודיים באופן אוטומטי.

דוגמה לתהליך עבודה של העברה

הקוד הבא מגדיר את מבנה הטבלה ואת הרצף שקשור אליה ב-Spanner באמצעות אובייקט SEQUENCE, ומגדיר את האובייקט כערך הראשי שמוגדר כברירת מחדל בטבלת היעד:

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(GoogleSQL או PostgreSQL).

הערכים האלה מפולגים באופן אחיד בטווח [1, 263] ויכול להיות שיהיו התנגשויות עם המפתחות הקיימים. כדי למנוע את זה, אפשר להגדיר את הרצף באמצעות ALTER_SEQUENCE (GoogleSQL או PostgreSQL) כדי לדלג על טווח הערכים שמכוסה על ידי המפתחות הקיימים.

נניח שהטבלה singers הועברה מ-PostgreSQL, ושמפתח ראשי singer_id שלה הוא מסוג SERIAL. הקוד הבא של PostgreSQL מציג את ה-DDL של מסד הנתונים שלכם:

PostgreSQL

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

הערכים של המפתח הראשי גדלים באופן מונוטוני. אחרי ההעברה, אפשר לאחזר את הערך המקסימלי של המפתח הראשי singer_id ב-Spanner. משתמשים בקוד הבא ב-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 או מסד הנתונים של המקור יוצרים מפתחות ראשיים. לדוגמה, כדי להפעיל רפליקציה בשני הכיוונים לצורך תוכנית התאוששות מאסון (DR) במהלך מעבר חד למערכת אחרת (cutover) של העברה.

כדי לתמוך בכך, שני מסדי הנתונים יוצרים מפתחות ראשיים והנתונים מסונכרנים ביניהם. אפשר להגדיר כל מסד נתונים כך שיצור מפתחות ראשיים בטווחים לא חופפים של מפתחות. כשמגדירים טווח למסד הנתונים של המקור, אפשר להגדיר את רצף Spanner כך שידלג על הטווח הזה.

לדוגמה, אחרי ההעברה של אפליקציית רצועות המוזיקה, אפשר לשכפל את הנתונים מ-PostgreSQL ל-Spanner כדי לקצר את הזמן שנדרש למעבר.

אחרי שמעדכנים את האפליקציה ב-Spanner ובודקים אותה, אפשר להפסיק להשתמש במסד הנתונים של PostgreSQL ולעבור ל-Spanner. כך, Spanner יהפוך למערכת הרשומות לעדכונים ולמפתחות ראשיים חדשים. כש-Spanner משתלט, אפשר להפוך את זרימת הנתונים בין מסדי הנתונים למופע PostgreSQL.

נניח שמסד הנתונים של PostgreSQL שמשמש כמקור משתמש בSERIAL מפתחות ראשיים, שהם מספרים שלמים חתומים בני 32 ביט. מפתחות ראשיים ב-Spanner הם מספרים גדולים יותר של 64 ביט. ב-PostgreSQL, משנים את עמודת המפתח הראשי לעמודה של 64 ביט או ל-bigint. משתמשים בקוד הבא במסד הנתונים של PostgreSQL:

PostgreSQL

ALTER TABLE Singers ALTER COLUMN SingerId TYPE bigint;

אפשר להגדיר אילוץ CHECK בטבלה במסד הנתונים של PostgreSQL כמקור כדי לוודא שהערכים של המפתח הראשי 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 שנוצרו במקום אחר משתלבים עם מפתחות UUID חדשים שנוצרו ב-Spanner.

כדאי לשקול את האסטרטגיה הבאה ברמה גבוהה להעברת מפתחות UUID אל Spanner:

  1. מגדירים את מפתחות ה-UUID ב-Spanner באמצעות עמודות מחרוזת עם ביטוי ברירת מחדל. משתמשים בפונקציה GENERATE_UUID() (GoogleSQL, PostgreSQL).
  2. מייצאים את הנתונים ממערכת המקור, ומבצעים סריאליזציה של מפתחות ה-UUID כמחרוזות.
  3. מייבאים את המפתחות הראשיים ל-Spanner.
  4. אופציונלי: הפעלת מפתחות זרים.

דוגמה לתהליך העברה:

ב-Spanner, מגדירים עמודה של מפתח ראשי מסוג UUID כ-STRING או כ-TEXT, ומקצים לה את הערך GENERATE_UUID()(GoogleSQL או PostgreSQL) כערך ברירת המחדל. מעבירים את כל הנתונים ממסד הנתונים של המקור אל Spanner. אחרי ההעברה, כשמוסיפים שורות חדשות, Spanner קורא לפונקציה GENERATE_UUID() כדי ליצור ערכי UUID חדשים למפתחות הראשיים. לדוגמה, המפתח הראשי FanClubId מקבל ערך UUIDv4 כשמוסיפים שורה חדשה לטבלה FanClubs. משתמשים בקוד הבא ב-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, אפשר ליצור מפתח מורכב שמשלב ערך עם פיזור אחיד, כמו hash, כרכיב הראשון, ואת המפתח העוקב כרכיב השני. כך תוכלו לשמור על ערכי המפתח הרציפים, בלי ליצור נקודות חמות בהיקף רחב. כדאי לעיין בתהליך העבודה הבא להעברה:

נניח שאתם צריכים להעביר טבלת MySQL‏ students עם מפתח ראשי AUTO_INCREMENT ל-Spanner. משתמשים בקוד הבא במסד הנתונים של MySQL:

MySQL

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

ב-Spanner, אפשר להוסיף עמודה שנוצרה StudentIdHash על ידי יצירת גיבוב (hash) של העמודה StudentId. לדוגמה:

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

העברת עמודות מפתח עוקבות

אם מערכת מסד הנתונים של המקור יוצרת ערכים עוקבים עבור עמודת מפתח, אפשר להשתמש ברצף חיובי עם היפוך סיביות (GoogleSQL,‏ PostgreSQL) בסכימת Spanner כדי ליצור ערכים שמתפלגים באופן שווה על פני מרחב המספרים השלמים החיוביים של 64 ביט. כדי למנוע מהרצף של Spanner ליצור ערך שחופף לערך שהועבר, אפשר להגדיר לו טווח דילוג.

לדוגמה, אפשר לדלג על הטווח מ-1 עד 4,294,967,296 (2^32) בשתי הסדרות הבאות, אם ידוע שמסד הנתונים של המקור יוצר רק מספרים שלמים בני 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 עם סדר ביטים הפוך (GoogleSQL,‏ PostgreSQL) כדי להמשיך ליצור ערכים כאלה. כדי להימנע מיצירת ערכים כפולים, אפשר להגדיר את הרצף כך שהמונה שלו יתחיל ממספר מותאם אישית.

לדוגמה, אם הפכתם מספרים מ-1 עד 1,000 כדי ליצור ערכים של מפתח ראשי, הרצף של 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;

המאמרים הבאים