במאמר הזה מוסבר איך לכתוב חותמת זמן של ביצוע פעולת commit לכל פעולת הוספה ועדכון שמבצעים ב-Spanner. כדי להשתמש בתכונה הזו, צריך להגדיר את האפשרות allow_commit_timestamp בעמודה TIMESTAMP, ואז לכתוב את חותמת הזמן כחלק מכל עסקה.
סקירה כללית
חותמת הזמן של ביצוע השינוי, שמבוססת על טכנולוגיית TrueTime, היא השעה שבה מתבצע שינוי בעסקה במסד הנתונים. האפשרות allow_commit_timestamp בעמודה מאפשרת לאחסן את חותמת הזמן של הקומיט בעמודה באופן אטומי.
באמצעות חותמות הזמן של השמירה שמאוחסנות בטבלאות, אפשר לקבוע את הסדר המדויק של השינויים ולבנות תכונות כמו יומני שינויים.
כדי להוסיף חותמות זמן של ביצוע שינויים למסד הנתונים:
יוצרים עמודה עם הסוג
TIMESTAMPעם אפשרות העמודהallow_commit_timestampשמוגדרת ל-trueבהגדרת הסכימה. לדוגמה:CREATE TABLE Performances ( ... LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true) ... ) PRIMARY KEY (...);אם אתם מבצעים פעולות הוספה או עדכון באמצעות DML, משתמשים בפונקציה
PENDING_COMMIT_TIMESTAMPכדי לכתוב את חותמת הזמן של השמירה.אם אתם מבצעים הוספות או עדכונים באמצעות מוטציות, השתמשו במחרוזת placeholder
spanner.commit_timestamp()בהוספות או בעדכונים של עמודת חותמת הזמן של השליחה. אפשר גם להשתמש בקבוע של חותמת הזמן של השליחה שסופק על ידי ספריית הלקוח. לדוגמה, הקבוע הזה בלקוח Java הואValue.COMMIT_TIMESTAMP.
כש-Spanner מבצע את הטרנזקציה באמצעות הפלייסולדרים האלה כערכי עמודות, חותמת הזמן של הביצוע בפועל נכתבת בעמודה שצוינה (לדוגמה: העמודה LastUpdateTime). אחר כך תוכלו להשתמש בערך של העמודה הזו כדי ליצור היסטוריה של עדכונים בטבלה.
אין ערובה לכך שערכי חותמת הזמן של השמירה יהיו ייחודיים. יכול להיות שטרנזקציות שכותבות לקבוצות לא חופפות של שדות יקבלו את אותה חותמת זמן. לעסקאות שכותבות לקבוצות חופפות של שדות יש חותמות זמן ייחודיות.
חותמות הזמן של ביצוע השינויים ב-Spanner הן ברמת דיוק של מיקרו-שנייה, והן מומרות לננו-שניות כשהן מאוחסנות בעמודות TIMESTAMP.
יצירה ומחיקה של עמודה עם חותמת זמן של קומיט
משתמשים באפשרות העמודה allow_commit_timestamp כדי להוסיף או להסיר תמיכה בחותמות זמן של קומיטים:
- כשיוצרים טבלה חדשה כדי לציין שעמודה תומכת בחותמות זמן של ביצוע פעולות.
- כשמשנים טבלה קיימת:
- כדי להוסיף עמודה חדשה שתתמוך בחותמות זמן של ביצועים,
- כדי לשנות עמודה קיימת
TIMESTAMPכך שתתמוך בחותמות זמן של ביצועים, - כדי לשנות עמודה קיימת
TIMESTAMPולהסיר את התמיכה בחותמת הזמן של הקומיט
מפתחות ואינדקסים
אתם יכולים להשתמש בעמודה של חותמת הזמן של השמירה כעמודה של מפתח ראשי או כעמודה ללא מפתח. אפשר להגדיר מפתחות ראשיים כ-ASC או כ-DESC.
-
ASC(ברירת מחדל) – מפתחות עולים הם אידיאליים למענה על שאילתות החל מזמן ספציפי ואילך. -
DESC– מקשים בסדר יורד שומרים את השורות האחרונות בחלק העליון של הטבלה. הם מאפשרים גישה מהירה לרשומות האחרונות.
האפשרות allow_commit_timestamp חייבת להיות עקבית בכל המפתחות הראשיים של טבלאות האב והצאצא. אם האפשרות לא עקבית במפתחות הראשיים, Spanner מחזיר שגיאה. האפשרות הזו יכולה להיות לא עקבית רק כשיוצרים או מעדכנים את הסכימה.
שימוש בחותמות זמן של ביצוע פעולות (commit) בתרחישים הבאים יוצר נקודות חמות שמפחיתות את ביצועי הנתונים:
עמודת חותמת הזמן של ביצוע השינוי כחלק הראשון של המפתח הראשי של טבלה:
CREATE TABLE Users ( LastAccess TIMESTAMP NOT NULL, UserId INT64 NOT NULL, ... ) PRIMARY KEY (LastAccess, UserId);החלק הראשון של המפתח הראשי של אינדקס משני:
CREATE INDEX UsersByLastAccess ON Users(LastAccess)או
CREATE INDEX UsersByLastAccessAndName ON Users(LastAccess, FirstName)
נקודות חמות מפחיתות את ביצועי הנתונים, גם עם שיעורי כתיבה נמוכים. אין תקורה של ביצועים אם חותמות הזמן של השמירה מופעלות בעמודות שאינן עמודות מפתח ושלא נוסף להן אינדקס.
יצירת עמודה של חותמת זמן לשליחת שינויים
ה-DDL הבא יוצר טבלה עם עמודה שתומכת בחותמות זמן של ביצוע פעולות.
CREATE TABLE Performances (
SingerId INT64 NOT NULL,
VenueId INT64 NOT NULL,
EventDate Date,
Revenue INT64,
LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (SingerId, VenueId, EventDate),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE
הוספת האפשרות משנה את עמודת חותמת הזמן באופן הבא:
- אפשר להשתמש במחרוזת placeholder
spanner.commit_timestamp()(או בקבוע שסופק על ידי ספריית הלקוח) להוספות ולעדכונים. - העמודה יכולה להכיל רק ערכים שמתייחסים לעבר. מידע נוסף מופיע במאמר בנושא הוספת ערך משלכם לחותמת הזמן.
האפשרות allow_commit_timestamp היא תלוית אותיות רישיות.
הוספת עמודה של חותמת זמן של ביצוע Commit לטבלה קיימת
כדי להוסיף עמודה של חותמת זמן של ביצוע Commit לטבלה קיימת, משתמשים בהצהרה ALTER TABLE. לדוגמה, כדי להוסיף עמודה LastUpdateTime לטבלה Performances
משתמשים בהצהרה הבאה:
ALTER TABLE Performances ADD COLUMN LastUpdateTime TIMESTAMP
NOT NULL OPTIONS (allow_commit_timestamp=true)
המרת עמודה של חותמות זמן לעמודה של חותמות זמן של ביצוע
אפשר להמיר עמודה קיימת של חותמות זמן לעמודה של חותמות זמן של ביצוע פעולת Commit, אבל כדי לעשות את זה, Spanner צריך לוודא שערכי חותמות הזמן הקיימים הם מהעבר. לדוגמה:
ALTER TABLE Performances ALTER COLUMN LastUpdateTime
SET OPTIONS (allow_commit_timestamp=true)
אי אפשר לשנות את סוג הנתונים או את הביאור NULL של עמודה בהצהרה ALTER TABLE שכוללת SET OPTIONS. פרטים נוספים זמינים במאמר בנושא שפת הגדרת נתונים.
הסרת האפשרות של חותמת הזמן של הקומיט
כדי להסיר את התמיכה בחותמת הזמן של ביצוע השינויים מעמודה, משתמשים באפשרות allow_commit_timestamp=null בהצהרה ALTER TABLE. ההתנהגות של חותמת הזמן של השמירה מוסרת, אבל העמודה עדיין מכילה חותמת זמן. שינוי האפשרות לא משנה מאפיינים אחרים של העמודה, כמו סוג או אפשרות לערך null (NOT NULL). לדוגמה:
ALTER TABLE Performances ALTER COLUMN LastUpdateTime
SET OPTIONS (allow_commit_timestamp=null)
כתיבת חותמת זמן של ביצוע באמצעות פקודת DML
משתמשים בפונקציה PENDING_COMMIT_TIMESTAMP כדי לכתוב את חותמת הזמן של ביצוע השינוי בפקודת DML. מערכת Spanner בוחרת את חותמת הזמן של השמירה כשמתבצעת שמירה של הטרנזקציה.
פקודת ה-DML הבאה מעדכנת את העמודה LastUpdateTime בטבלה Performances עם חותמת הזמן של השמירה:
UPDATE Performances SET LastUpdateTime = PENDING_COMMIT_TIMESTAMP()
WHERE SingerId=1 AND VenueId=2 AND EventDate="2015-10-21"
בדוגמת הקוד הבאה נעשה שימוש בפונקציה PENDING_COMMIT_TIMESTAMP כדי לכתוב את חותמת הזמן של השליחה בעמודה LastUpdateTime.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Ruby
אפשר לכתוב חותמות זמן של ביצוע פעולות רק בעמודות עם ההערה allow_commit_timestamp=true.
אם יש לכם מוטציות בשורות בכמה טבלאות, אתם צריכים לציין spanner.commit_timestamp() (או את הקבוע של ספריית הלקוח) בעמודה של חותמת הזמן של השמירה בכל טבלה.
שאילתה של עמודה עם חותמת זמן של ביצוע שינוי
בדוגמה הבאה מוצגת שאילתה של עמודת חותמת הזמן של ביצוע השינוי בטבלה.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
הזנת ערך משלכם בעמודה של חותמת הזמן של השליחה
אתם יכולים לספק ערך משלכם לעמודה של חותמת הזמן של השליחה, במקום להעביר את הערך spanner.commit_timestamp() (או קבוע של ספריית לקוח) כערך של העמודה. הערך חייב להיות חותמת זמן שמתייחסת לזמן שכבר חלף. המגבלה הזו מבטיחה שפעולת הכתיבה של חותמות הזמן תהיה זולה ומהירה. השרת
מחזיר שגיאת FailedPrecondition אם מצוינת חותמת זמן עתידית.
יצירת יומן שינויים
נניח שאתם רוצים ליצור יומן שינויים של כל מוטציה שמתרחשת בטבלה, ואז להשתמש ביומן השינויים הזה לצורך ביקורת. דוגמה: טבלה שמאחסנת את היסטוריית השינויים במסמכים של מעבד תמלילים. חותמת הזמן של הקומיט מקלה על יצירת יומן השינויים, כי חותמות הזמן יכולות לאכוף את הסדר של הרשומות ביומן השינויים. אפשר ליצור יומן שינויים שבו מאוחסנת היסטוריית השינויים במסמך מסוים באמצעות סכימה כמו בדוגמה הבאה:
CREATE TABLE Documents (
UserId INT64 NOT NULL,
DocumentId INT64 NOT NULL,
Contents STRING(MAX) NOT NULL,
) PRIMARY KEY (UserId, DocumentId);
CREATE TABLE DocumentHistory (
UserId INT64 NOT NULL,
DocumentId INT64 NOT NULL,
Ts TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
Delta STRING(MAX),
) PRIMARY KEY (UserId, DocumentId, Ts),
INTERLEAVE IN PARENT Documents ON DELETE NO ACTION;
כדי ליצור יומן שינויים, מוסיפים שורה חדשה ב-DocumentHistory באותה טרנזקציה שבה מוסיפים או מעדכנים שורה ב-Document. כשמוסיפים את השורה החדשה ב-DocumentHistory, משתמשים ב-placeholder spanner.commit_timestamp() (או בקבוע של ספריית הלקוח) כדי להנחות את Spanner לכתוב את חותמת הזמן של השמירה בעמודה Ts. שילוב של טבלת DocumentsHistory עם טבלת Documents יאפשר לנתונים להיות מקומיים ויעיל יותר להוסיף ולעדכן אותם. עם זאת, היא מוסיפה גם את האילוץ ששורות ההורה והילד חייבות להימחק יחד. כדי שהשורות בטבלה DocumentHistory יישארו אחרי שהשורות בטבלה Documents יימחקו, אל תשלבו בין הטבלאות.
אופטימיזציה של שאילתות על נתונים מהזמן האחרון באמצעות חותמות זמן של ביצוע פעולות
חותמות הזמן של ביצוע השינויים מאפשרות לבצע אופטימיזציה ב-Spanner, שיכולה לצמצם את קלט/פלט השאילתות כשמאחזרים נתונים שנכתבו אחרי זמן מסוים.
כדי להפעיל את האופטימיזציה הזו, סעיף WHERE של שאילתה צריך לכלול השוואה בין עמודת חותמת הזמן של ביצוע השינויים בטבלה לבין זמן ספציפי שאתם מספקים, עם המאפיינים הבאים:
מציינים את השעה הספציפית כביטוי קבוע: ערך מילולי, פרמטר או פונקציה שהארגומנטים שלה הם קבועים.
אפשר להשוות בין חותמת הזמן של הקומיט לבין הזמן שצוין באמצעות האופרטורים
>או>=.אופציונלי: מוסיפים הגבלות נוספות לסעיף
WHEREבאמצעותAND. הוספת התנאיORלפסקה גורמת לכך שהשאילתה לא עומדת בדרישות של האופטימיזציה הזו.
לדוגמה, נניח שיש לכם את הטבלה Performances הבאה, שכוללת עמודה של חותמת זמן של ביצוע commit:
CREATE TABLE Performances (
SingerId INT64 NOT NULL,
VenueId INT64 NOT NULL,
EventDate DATE,
Revenue INT64,
LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (SingerId, VenueId, EventDate);
השאילתה הזו נהנית מהאופטימיזציה של חותמת הזמן של השליחה שמתוארת למעלה, כי יש בה השוואה של גדול או שווה בין עמודת חותמת הזמן של השליחה של הטבלה לבין ביטוי קבוע – במקרה הזה, ערך מילולי:
SELECT * FROM Performances WHERE LastUpdateTime >= "2022-05-01";
גם השאילתה הבאה עומדת בדרישות לאופטימיזציה, כי יש בה השוואה מסוג 'גדול מ' בין חותמת הזמן של השליחה לבין פונקציה שכל הארגומנטים שלה מוערכים כקבועים במהלך ההרצה של השאילתה:
SELECT * FROM Performances
WHERE LastUpdateTime > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY);
המאמרים הבאים
- אפשר להשתמש בחותמות זמן של השמירה כדי ליצור יומן שינויים באמצעות Go.