שיטות מומלצות לעדכון סכימה

במאמר הזה מפורטות שיטות מומלצות לעדכון סכימות.

פעולות שצריך לבצע לפני שמתחילים לעדכן את הסכימה

לפני שמבצעים עדכון סכימה:

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

    • אם מוסיפים הערה NOT NULL לעמודה קיימת, צריך לוודא שהעמודה לא מכילה ערכים קיימים של NULL.
    • אם מקצרים את האורך המותר של עמודה מסוג STRING או BYTES, צריך לוודא שכל הערכים הקיימים בעמודה הזו עומדים במגבלת האורך.
  • אם אתם כותבים לעמודה, לטבלה או לאינדקס שעוברים עדכון סכימה, ודאו שהערכים שאתם כותבים עומדים באילוצים החדשים.

  • אם אתם משמיטים עמודה, טבלה או אינדקס, אתם צריכים לוודא שאתם לא עדיין כותבים לתוכם או קוראים מהם.

הגבלת התדירות של עדכוני סכימה

אם מבצעים יותר מדי עדכוני סכימה בפרק זמן קצר, יכול להיות ש-Spanner throttle את העיבוד של עדכוני הסכימה שנמצאים בתור. הסיבה לכך היא שב-Spanner יש מגבלה על נפח האחסון של גרסאות סכימה. יכול להיות שהעדכון של הסכימה יוגבל אם יש יותר מדי גרסאות ישנות של הסכימה בתוך תקופת השמירה. הקצב המקסימלי של שינויים בסכימה תלוי בהרבה גורמים, ואחד מהם הוא המספר הכולל של העמודות במסד הנתונים. לדוגמה, במסד נתונים עם 2,000 עמודות (בערך 2,000 שורות ב-INFORMATION_SCHEMA.COLUMNS) אפשר לבצע לכל היותר 1,500 שינויים בסכימה (פחות אם השינוי בסכימה דורש כמה גרסאות) במהלך תקופת השמירה. כדי לראות את המצב של עדכוני סכימה שמתבצעים, משתמשים בפקודה gcloud spanner operations list ומסננים לפי פעולות מהסוג DATABASE_UPDATE_DDL. כדי לבטל עדכון סכימה שמתבצע, משתמשים בפקודה gcloud spanner operations cancel ומציינים את מזהה הפעולה.

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

כפי שמתואר בגרסאות סכימה, חלק מהצהרות ה-DDL יוצרות כמה גרסאות סכימה, והן חשובות כששוקלים את האפשרות של עיבוד באצווה ואת הסדר בתוך כל אצווה. יש שני סוגים עיקריים של הצהרות שעשויות ליצור כמה גרסאות של סכימה:

  • הצהרות שעשויות לדרוש מילוי חוסרים (backfill) של נתוני אינדקס, כמו CREATE INDEX.
  • הצהרות שמאלצות את Spanner לאמת נתונים קיימים, כמו הוספה של NOT NULL או אילוצי אורך.

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

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

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

סדר הביצוע של הצהרות בחבילות

אם אתם משתמשים ב-Google Cloud CLI, ב-API בארכיטקטורת REST או ב-RPC API, אתם יכולים להנפיק קבוצה של הצהרות CREATE, ALTER או DROP .

‫Spanner מחיל את ההצהרות מאותו אצווה לפי הסדר, ומפסיק כשהוא נתקל בשגיאה הראשונה. אם יישום של הצהרה מסוימת מוביל לשגיאה, המערכת מבטלת את הפעולה שבוצעה בהצהרה הזו. התוצאות של כל ההצהרות שהוחלו בעבר על האצווה לא יבוטלו. המשמעות של יישום ההצהרות לפי הסדר היא שאם רוצים שהצהרות שדורשות מילוי חוסרים בלתי נמנע יפעלו במקביל (למשל, יצירת כמה אינדקסים בטבלאות גדולות קיימות), צריך לשלוח את ההצהרות האלה באצוות נפרדות, כי כל מילוי חוסרים יכול להימשך זמן רב. אם יוצרים טבלה חדשה עם אינדקסים, השיטה המומלצת היא למקם אותם יחד (CREATE TABLE ואחריו CREATE INDEX) באותו אצווה כדי להימנע לחלוטין מהשלמת חוסרים.

יכול להיות ש-Spanner ישלב ויסדר מחדש הצהרות מחבילות שונות, ויערבב הצהרות מחבילות שונות לשינוי אטומי אחד שמוחל על מסד הנתונים. בכל שינוי אטומי, ההצהרות מקבוצות שונות מתבצעות בסדר שרירותי. לדוגמה, אם חבילה אחת של הצהרות מכילה ALTER TABLE table_name ALTER COLUMN column_name STRING(50) וחבילה אחרת של הצהרות מכילה ALTER TABLE table_name ALTER COLUMN column_name STRING(20), ‏ Spanner ישאיר את העמודה הזו באחד משני המצבים האלה, אבל המצב שבו היא תישאר לא נקבע מראש.

אפשרויות לעדכונים גדולים של סכימות

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

אם נדרש למשפט למלא מחדש נתוני אינדקס או לבצע אימות נתונים, אי אפשר להריץ אותו בגרסת סכימה אחת. המצב הזה קורה לגבי CREATE INDEX הצהרות אם טבלת הבסיס של האינדקס כבר קיימת (או כי היא נוצרה בסדרת הצהרות DDL קודמת, או כי הייתה הצהרה בסדרה בין ההצהרות CREATE TABLE ו-CREATE INDEX שדרשה כמה גרסאות סכימה). ב-Spanner, אסור לכלול יותר מ-10 הצהרות כאלה באצווה אחת. יצירת אינדקס שמחייבת מילוי חוסרים, בפרט, משתמשת בכמה גרסאות סכימה לכל אינדקס, ולכן מומלץ ליצור לא יותר מ-3 אינדקסים חדשים שמחייבים מילוי חוסרים ביום (לא משנה איך הם מקובצים, אלא אם הקיבוץ יכול למנוע מילוי חוסרים).

לדוגמה, קבוצת ההצהרות הזו תשתמש בגרסה אחת של סכימה:

GoogleSQL

CREATE TABLE Singers (
SingerId   INT64 NOT NULL,
FirstName  STRING(1024),
LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE INDEX SingersByFirstName ON Singers(FirstName);

CREATE INDEX SingersByLastName ON Singers(LastName);

CREATE TABLE Albums (
SingerId   INT64 NOT NULL,
AlbumId    INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);

לעומת זאת, באצווה הזו נעשה שימוש בגרסאות סכימה רבות, כי UnrelatedIndex דורש מילוי חוזר (כי טבלת הבסיס שלו כבר הייתה קיימת), וזה גורם לכך שגם כל האינדקסים הבאים דורשים מילוי חוזר (למרות שהם באותה אצווה כמו טבלאות הבסיס שלהם):

GoogleSQL

CREATE TABLE Singers (
SingerId   INT64 NOT NULL,
FirstName  STRING(1024),
LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
SingerId   INT64 NOT NULL,
AlbumId    INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey);

CREATE INDEX SingersByFirstName ON Singers(FirstName);

CREATE INDEX SingersByLastName ON Singers(LastName);

CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);

מומלץ להעביר את היצירה של UnrelatedIndex לסוף של הקבוצה או לקבוצה אחרת, כדי לצמצם את מספר הגרסאות של הסכימה.

המתנה לסיום בקשות ה-API

כששולחים בקשות projects.instances.databases.updateDdl (API בארכיטקטורת REST) או UpdateDatabaseDdl (RPC API), משתמשים ב-projects.instances.databases.operations.get (API בארכיטקטורת REST) או ב-GetOperation (RPC API), בהתאמה, כדי להמתין להשלמת כל בקשה לפני שמתחילים בקשה חדשה. המתנה לסיום כל בקשה מאפשרת לאפליקציה לעקוב אחרי התקדמות העדכונים של הסכימה. בנוסף, הוא שומר את רשימת העדכונים הממתינים של הסכימה בגודל שניתן לניהול.

טעינה בכמות גדולה

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

אם טוענים את הנתונים קודם ואז יוצרים אינדקסים, קליטת הנתונים מהירה יותר כי רק הטבלה נכתבת, ומילוי החסר של האינדקסים מאוחר יותר יכול לכתוב את נתוני האינדקס באצוות ממוטבות שיעילות יותר מכתיבת נתוני האינדקס יחד עם נתוני הטבלה. עם זאת, כדי למלא מחדש אינדקסים נדרשות כמה גרסאות סכימה, ויש מגבלות על הפעולה הזו. כמו שצוין באפשרויות לעדכונים גדולים, לא מומלץ ליצור יותר מ-10 אינדקסים שנדרש למלא אותם מחדש באצווה אחת, ועדיף ליצור לא יותר מ-3 אינדקסים כאלה ביום.

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

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