בדף הזה מוסבר איך לכתוב חותמת זמן של ביצוע פעולת קומיט לכל פעולת הוספה ועדכון שמבצעים ב-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#
Go
Java
Node.js
PHP
Python
Ruby
אם יש לכם שינויים בשורות בכמה טבלאות, אתם צריכים לציין spanner.commit_timestamp() (או קבוע של ספריית לקוח) בעמודה של חותמת הזמן של השמירה בכל טבלה.
עדכון שורה באמצעות מוטציה
כשמעדכנים שורה, Spanner כותב את הערך של חותמת הזמן של ביצוע השינוי רק אם כוללים את העמודה ברשימת העמודות ומעבירים את מחרוזת ה-placeholder spanner.commit_timestamp() (או קבוע של ספריית הלקוח) כערך שלה. אי אפשר לעדכן את המפתח הראשי של שורה. כדי לעדכן את המפתח הראשי, צריך למחוק את השורה הקיימת וליצור שורה חדשה.
לדוגמה, כדי לעדכן עמודה של חותמת זמן של קומיט בשם LastUpdateTime:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
אם יש לכם מוטציות בשורות בכמה טבלאות, אתם צריכים לציין spanner.commit_timestamp() (או את הקבוע של ספריית הלקוח) בעמודה של חותמת הזמן של השמירה בכל טבלה.
שאילתה של עמודה עם חותמת זמן של ביצוע שינוי
בדוגמה הבאה מוצגת שאילתה של עמודת חותמת הזמן של ביצוע השינוי בטבלה.
C++
C#
Go
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 יימחקו, אל תשלבו את הטבלאות.
אופטימיזציה של שאילתות על נתונים מהזמן האחרון באמצעות חותמות זמן של ביצוע פעולות
חותמות זמן של ביצוע פעולות (commit) עוזרות לבצע אופטימיזציה של מסד הנתונים ב-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';