בדף הזה מוסבר איך לכתוב חותמת זמן של ביצוע פעולת קומיט לכל פעולת הוספה ועדכון שמבצעים ב-Spanner במסדי נתונים בניב PostgreSQL.
הוספת חותמות זמן של קומיטים
חותמת הזמן של השמירה, שמבוססת על הטכנולוגיה TrueTime, היא הזמן שבו העסקה נשמרת במסד הנתונים. אפשר לאחסן באופן אטומי את חותמת הזמן של ביצוע השינויים בעסקה בעמודה. באמצעות חותמות הזמן של השמירה שמאוחסנות בטבלאות, אפשר לקבוע את הסדר המדויק של השינויים ולבנות תכונות כמו יומני שינויים.
כדי להוסיף חותמות זמן של ביצועים למסד הנתונים:
יוצרים עמודה מהסוג
SPANNER.COMMIT_TIMESTAMP. לדוגמה:CREATE TABLE Performances ( ... LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL, ... PRIMARY KEY (...) ) ;אם אתם מבצעים הוספות או עדכונים באמצעות DML, אתם יכולים להשתמש בפונקציה
SPANNER.PENDING_COMMIT_TIMESTAMP()כדי לכתוב את חותמת הזמן של השמירה.אם אתם מבצעים הוספות או עדכונים באמצעות הצהרות מוכנות או מוטציות, השתמשו במחרוזת placeholder
SPANNER.COMMIT_TIMESTAMP()עבור עמודת חותמת הזמן של השמירה. אפשר גם להשתמש בקבוע של חותמת הזמן של השמירה שסופק על ידי ספריית הלקוח. לדוגמה, הקבוע הזה בלקוח Java הואValue.COMMIT_TIMESTAMP.
כש-Spanner מבצע את הטרנזקציה באמצעות הפלייסהולדרים האלה כערכי עמודות, חותמת הזמן בפועל של השמירה נכתבת בעמודה שצוינה. אחר כך אפשר להשתמש בערך של העמודה הזו כדי ליצור היסטוריה של עדכונים בטבלה.
אין ערובה לכך שערכי חותמת הזמן של השמירה יהיו ייחודיים. יכול להיות שחותמת הזמן של טרנזקציות שכותבות לקבוצות שדות לא חופפות תהיה זהה. לעסקאות שכותבות לקבוצות חופפות של שדות יש חותמות זמן ייחודיות.
חותמות הזמן של ביצוע פעולות commit ב-Spanner הן ברמת דיוק של מיקרו-שנייה, והן מומרות לננו-שניות כשהן מאוחסנות בעמודות SPANNER.COMMIT_TIMESTAMP.
מפתחות ואינדקסים
אתם יכולים להשתמש בעמודה של חותמת הזמן של השמירה כעמודה של מפתח ראשי או כעמודה ללא מפתח. אפשר להגדיר מפתחות ראשיים כ-ASC או כ-DESC.
-
ASC(ברירת מחדל) – מפתחות בסדר עולה הם אידיאליים למענה על שאילתות החל מזמן ספציפי. -
DESC– מקשים בסדר יורד שומרים את השורות האחרונות בחלק העליון של הטבלה. הם מאפשרים גישה מהירה לרשומות האחרונות.
הימנעות מנקודות חמות
שימוש בחותמות זמן של ביצוע פעולות (commit) בתרחישים הבאים יוצר נקודות חמות, שפוגעות בביצועים של הנתונים:
עמודת חותמת הזמן של ביצוע השינוי כחלק הראשון של המפתח הראשי של טבלה.
CREATE TABLE Users ( LastAccess SPANNER.COMMIT_TIMESTAMP NOT NULL, UserId bigint NOT NULL, ... PRIMARY KEY (LastAccess, UserId) ) ;העמודה של המפתח הראשי של חותמת הזמן של השמירה כחלק הראשון של אינדקס משני.
CREATE INDEX UsersByLastAccess ON Users(LastAccess)או
CREATE INDEX UsersByLastAccessAndName ON Users(LastAccess, FirstName)
נקודות חמות מפחיתות את ביצועי הנתונים, גם אם שיעורי הכתיבה נמוכים. אין תקורה של ביצועים אם חותמות הזמן של ביצוע השינויים מופעלות בעמודות שאינן עמודות מפתח ושלא נוספו להן אינדקסים.
הוספת עמודה של חותמת זמן של ביצוע Commit לטבלה קיימת
כדי להוסיף עמודה של חותמת זמן של ביצוע Commit לטבלה קיימת, משתמשים בהצהרת ALTER TABLE. לדוגמה, כדי להוסיף עמודה LastUpdateTime לטבלה Performances
משתמשים בהצהרה הבאה:
ALTER TABLE Performances ADD COLUMN LastUpdateTime SPANNER.COMMIT_TIMESTAMP;
כתיבת חותמת זמן של ביצוע באמצעות פקודת DML
משתמשים בפונקציה SPANNER.PENDING_COMMIT_TIMESTAMP() כדי לכתוב את חותמת הזמן של השמירה בפקודת DML. מערכת Spanner בוחרת את חותמת הזמן של השמירה כשמתבצעת שמירה של הטרנזקציה.
פקודת ה-DML הבאה מעדכנת את העמודה LastUpdateTime בטבלה Performances עם חותמת הזמן של השמירה:
UPDATE Performances SET LastUpdateTime = SPANNER.PENDING_COMMIT_TIMESTAMP()
WHERE SingerId=1 AND VenueId=2 AND EventDate="2015-10-21"
הוספת שורה באמצעות מוטציה
כשמוסיפים שורה, Spanner כותב את הערך של חותמת הזמן של השמירה רק אם כוללים את העמודה ברשימת העמודות ומעבירים את מחרוזת ה-placeholder spanner.commit_timestamp() (או קבוע של ספריית לקוח) כערך שלה. לדוגמה:
C++
C#
המשך
Java
Node.js
PHP
Python
Ruby
אם יש לכם מוטציות בשורות בכמה טבלאות, אתם צריכים לציין spanner.commit_timestamp() (או קבוע של ספריית לקוח) בעמודה של חותמת הזמן של השמירה בכל טבלה.
עדכון שורה באמצעות מוטציה
כשמעדכנים שורה, Spanner כותב את הערך של חותמת הזמן של הקומיט רק אם כוללים את העמודה ברשימת העמודות ומעבירים את מחרוזת ה-placeholder spanner.commit_timestamp() (או קבוע של ספריית הלקוח) כערך שלה. אי אפשר לעדכן את המפתח הראשי של שורה. כדי לעדכן את המפתח הראשי, צריך למחוק את השורה הקיימת וליצור שורה חדשה.
לדוגמה, כדי לעדכן עמודה של חותמת זמן של ביצוע שינוי בשם LastUpdateTime:
C++
C#
המשך
Java
Node.js
PHP
Python
Ruby
אם יש לכם מוטציות בשורות בכמה טבלאות, אתם צריכים לציין spanner.commit_timestamp() (או את הקבוע של ספריית הלקוח) בעמודת חותמת הזמן של השליחה בכל טבלה.
שאילתה של עמודה עם חותמת זמן של ביצוע קומיט
בדוגמה הבאה מוצגת שאילתה של עמודת חותמת הזמן של ביצוע השינוי בטבלה.
C++
C#
המשך
Java
Node.js
PHP
Python
Ruby
הוספת ערך משלכם לעמודה של חותמת הזמן של השמירה
בקוד, אתם יכולים לספק ערך משלכם לעמודה של חותמת הזמן של השליחה במקום להעביר את הערך spanner.commit_timestamp() (או את הקבוע של ספריית הלקוח שזמין) כערך של העמודה. הערך חייב להיות חותמת זמן שמתייחסת לזמן שכבר חלף. ההגבלה הזו מבטיחה שפעולת הכתיבה של חותמות הזמן תהיה זולה ומהירה. דרך אחת לוודא שערך מסוים הוא מהעבר היא להשוות אותו לערך שמוחזר על ידי פונקציית ה-SQL CURRENT_TIMESTAMP. השרת מחזיר שגיאה מסוג FailedPrecondition אם מציינים חותמת זמן עתידית.
יצירת יומן שינויים
נניח שרוצים ליצור יומן שינויים של כל מוטציה שמתרחשת בטבלה, ואז להשתמש ביומן השינויים הזה לצורכי ביקורת. דוגמה לכך היא טבלה שמאחסנת את היסטוריית השינויים במסמכים של מעבד תמלילים. חותמת הזמן של השמירה מקלה על יצירת יומן השינויים, כי חותמות הזמן יכולות לאכוף את הסדר של הרשומות ביומן השינויים. אפשר ליצור יומן שינויים שבו מאוחסנת היסטוריית השינויים במסמך מסוים באמצעות סכימה כמו בדוגמה הבאה:
CREATE TABLE Documents (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Contents text NOT NULL,
PRIMARY KEY (UserId, DocumentId)
);
CREATE TABLE DocumentHistory (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Ts SPANNER.COMMIT_TIMESTAMP NOT NULL,
Delta text,
PRIMARY KEY (UserId, DocumentId, Ts)
) INTERLEAVE IN PARENT Documents;
כדי ליצור יומן שינויים, מוסיפים שורה חדשה ב-DocumentHistory באותה טרנזקציה שבה מוסיפים או מעדכנים שורה ב-Document. כשמוסיפים את השורה החדשה ב-DocumentHistory, משתמשים ב-placeholder spanner.commit_timestamp() (או בקבוע של ספריית הלקוח) כדי להנחות את Spanner לכתוב את חותמת הזמן של ביצוע השינויים בעמודה Ts.
שילוב של טבלה DocumentsHistory עם טבלה Documents מאפשר לוקאליות של נתונים ועדכונים והוספות יעילים יותר. עם זאת, היא גם מוסיפה את האילוץ שלפיו צריך למחוק את השורות של ההורה והילד ביחד. כדי שהשורות בטבלה DocumentHistory יישארו אחרי שהשורות בטבלה Documents יימחקו, אל תשלבו בין הטבלאות.
אופטימיזציה של שאילתות על נתונים מהזמן האחרון באמצעות חותמות זמן של ביצוע פעולות
חותמות זמן של ביצוע שינויים משפרות את מסד הנתונים של Spanner ויכולות להפחית את קלט/פלט השאילתות כשמאחזרים נתונים שנכתבו אחרי זמן מסוים.
כדי להפעיל את האופטימיזציה הזו, סעיף WHERE של שאילתה צריך לכלול השוואה בין עמודת חותמת הזמן של ביצוע השינויים בטבלה לבין זמן ספציפי שאתם מספקים, עם המאפיינים הבאים:
מציינים את השעה הספציפית כביטוי קבוע: ערך מילולי, פרמטר או פונקציה שהארגומנטים שלה הם קבועים.
אפשר להשוות בין חותמת הזמן של הקומיט לבין הזמן שצוין באמצעות האופרטורים
>או>=.אופציונלי: מוסיפים הגבלות נוספות לסעיף
WHEREבאמצעותAND. הוספת התנאיORלשאילתה גורמת לכך שהיא לא עומדת בדרישות של האופטימיזציה הזו.
לדוגמה, נניח שיש לכם את הטבלה Performances הבאה, שכוללת עמודה של חותמת זמן של ביצוע commit:
CREATE TABLE Performances (
SingerId bigint NOT NULL,
VenueId bigint NOT NULL,
EventDate timestamp with time zone NOT NULL,
Revenue bigint,
LastUpdateTime spanner.commit_timestamp,
PRIMARY KEY(SingerId, VenueId, EventDate)
);
השאילתה הזו נהנית מהאופטימיזציה של חותמת הזמן של ביצוע השינוי שתיארנו קודם, כי יש בה השוואה של גדול או שווה בין העמודה של חותמת הזמן של ביצוע השינוי בטבלה לבין ביטוי קבוע – במקרה הזה, ערך מילולי:
SELECT * FROM Performances WHERE LastUpdateTime >= '2022-01-01';