במאמר הזה מוסבר איך להשתמש בטבלאות המובנות של נתוני הנעילה ב-Spanner כדי לזהות את מפתחות השורות ואת עמודות הטבלה שגרמו להתנגשויות נעילה של טרנזקציות במסד הנתונים במהלך תקופה מסוימת. אפשר לאחזר נתונים סטטיסטיים מטבלאות SPANNER_SYS.LOCK_STATS* האלה באמצעות הצהרות SQL.
גישה לסטטיסטיקות של נעילת הגישה
Spanner מספק את נתוני הנעילה בסכימה SPANNER_SYS.
אפשר לגשת לנתוני SPANNER_SYS בדרכים הבאות:
דף Spanner Studio של מסד נתונים במסוף Google Cloud
מרכז הבקרה Lock insights.
השיטה
executeSqlאו השיטהexecuteStreamingSql.ה-methods הבאות של קריאה יחידה ש-Spanner מספק לא תומכות ב-
SPANNER_SYS:- ביצוע קריאה חזקה משורה אחת או מכמה שורות בטבלה.
- ביצוע קריאה בעבר משורה אחת או מכמה שורות בטבלה.
- קריאה משורה אחת או מכמה שורות באינדקס משני.
נעילת נתונים סטטיסטיים לפי מפתח שורה
בטבלאות הבאות אפשר לעקוב אחרי מפתח השורה עם זמן ההמתנה הכי ארוך:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE: מפתחות שורה עם זמני ההמתנה הגבוהים ביותר לנעילה במרווחי זמן של דקה אחת.
SPANNER_SYS.LOCK_STATS_TOP_10MINUTE: מפתחות שורה עם זמני ההמתנה הגבוהים ביותר לנעילה במרווחי זמן של 10 דקות.
SPANNER_SYS.LOCK_STATS_TOP_HOUR: מפתחות שורות עם זמני המתנה הכי ארוכים לנעילה במרווחי זמן של שעה
הטבלאות האלה כוללות את המאפיינים הבאים:
כל טבלה מכילה נתונים של מרווחי זמן לא חופפים באורך שצוין בשם הטבלה.
המרווחים מבוססים על שעות. מרווחי זמן של דקה אחת מסתיימים בתחילת הדקה, מרווחי זמן של 10 דקות מסתיימים כל 10 דקות החל מתחילת השעה, ומרווחי זמן של שעה אחת מסתיימים בתחילת השעה. אחרי כל מרווח זמן, מערכת Spanner אוספת נתונים מכל השרתים, ואז הנתונים האלה זמינים בטבלאות SPANNER_SYS זמן קצר לאחר מכן.
לדוגמה, בשעה 11:59:30, המרווחים האחרונים שזמינים לשאילתות SQL הם:
- דקה אחת: 11:58:00–11:58:59
- 10 דקות: 11:40:00–11:49:59
- שעה אחת: 10:00:00–10:59:59 AM
ב-Spanner, הנתונים הסטטיסטיים מקובצים לפי טווח מפתחות שורות התחלתי.
כל שורה מכילה נתונים סטטיסטיים לגבי זמן ההמתנה הכולל לנעילה של טווח מסוים של מפתחות שורות התחלתיים, ש-Spanner אוסף לגביו נתונים סטטיסטיים במהלך המרווח שצוין.
אם Spanner לא מצליח לאחסן מידע על כל טווח של מפתחות שורות להמתנה לנעילה במהלך המרווח, המערכת מתעדפת את טווח מפתחות השורות עם זמן ההמתנה לנעילה הגבוה ביותר במהלך המרווח שצוין.
כל העמודות בטבלאות הן nullable.
סכמת טבלאות
| שם העמודה | סוג | תיאור |
|---|---|---|
INTERVAL_END |
TIMESTAMP |
סוף מרווח הזמן שבו התרחשו ההתנגשויות של הנעילה שנכללות. |
ROW_RANGE_START_KEY |
BYTES(MAX) |
מפתח השורה שבה התרחשה התנגשות הנעילה. אם הקונפליקט כולל טווח של שורות, הערך הזה מייצג את מפתח ההתחלה של הטווח הזה. סימן הפלוס, +, מציין טווח.
מידע נוסף זמין במאמר מהו מפתח התחלה של טווח שורות.
|
LOCK_WAIT_SECONDS |
FLOAT64 |
משך ההמתנה המצטבר לנעילה של התנגשויות נעילה שתועדו עבור כל העמודות בטווח של מפתח השורה, בשניות. |
SAMPLE_LOCK_REQUESTS |
ARRAY<STRUCT<
|
כל רשומה במערך הזה תואמת לבקשת נעילה לדוגמה שתרמה להתנגשות הנעילה, על ידי המתנה לנעילה או חסימת טרנזקציות אחרות מלקבל את הנעילה, במפתח השורה (הטווח) הנתון. מספר הדגימות המקסימלי במערך הזה הוא 20.
כל דוגמה מכילה את שלושת השדות הבאים:
|
SAMPLE_LOCK_REQUESTS_JSON_STRING |
STRING |
ייצוג מחרוזת תואמת ל-JSON של העמודה SAMPLE_LOCK_REQUESTS. המחרוזת בפורמט JSON היא אובייקט JSON עם אותו מבנה כמו STRUCT שמוגדר בעמוד SAMPLE_LOCK_REQUESTS.
העמודה הזו נתמכת במסדי נתונים של GoogleSQL-dialect ו-PostgreSQL-dialect. |
מצבי נעילה
פעולות ב-Spanner מקבלות נעילות כשהן חלק מעסקת קריאה-כתיבה. עסקאות לקריאה בלבד לא מקבלות נעילות. ב-Spanner נעשה שימוש במצבי נעילה שונים כדי למקסם את מספר העסקאות שיש להן גישה לתא נתונים מסוים בזמן נתון. לסוגים שונים של נעילות יש מאפיינים שונים. לדוגמה, אפשר לשתף נעילות מסוימות בין כמה עסקאות, אבל אי אפשר לשתף נעילות אחרות.
התנגשות נעילה יכולה להתרחש כשמנסים להשיג אחד ממצבי הנעילה הבאים בטרנזקציה.
ReaderSharedנעילה – נעילה שמאפשרת לגישות קריאה אחרות לגשת לנתונים עד שהעסקה מוכנה להתחייבות. הנעילה המשותפת הזו מתבצעת כשעסקה לקריאה וכתיבה קוראת נתונים.WriterSharedנעילה – הנעילה הזו מתבצעת כשטרנזקציית קריאה-כתיבה מנסה לבצע כתיבה.Exclusiveנעילה – נעילה בלעדית מתבצעת כשטרנזקציה של קריאה וכתיבה, שכבר קיבלה נעילה מסוג ReaderShared, מנסה לכתוב נתונים אחרי השלמת הקריאה. נעילה בלעדית היא שדרוג מנעילתReaderShared. נעילה בלעדית היא מקרה מיוחד של טרנזקציה שבה מוחזקות בו-זמנית גם נעילתReaderSharedוגם נעילתWriterShared. אף טרנזקציה אחרת לא יכולה לקבל נעילה באותו תא.WriterSharedTimestampנעילה – סוג מיוחד שלWriterSharedנעילה שמתקבלת כשמוסיפים שורות חדשות לטבלה שיש בה חותמת זמן של ביצוע שינויים כחלק מהמפתח הראשי. סוג הנעילה הזה מונע ממשתתפים בעסקה ליצור את אותה שורה בדיוק, וכך למנוע התנגשות ביניהם. מערכת Spanner מעדכנת את המפתח של השורה שהוכנסה כך שיתאים לחותמת הזמן של האישור של העסקה שביצעה את ההוספה.
מידע נוסף על סוגי עסקאות ועל סוגי הנעילות שזמינים מופיע במאמר עסקאות.
התנגשויות במצב נעילה
בטבלה הבאה מוצגים העימותים האפשריים בין מצבי נעילה שונים.
| מצבי נעילה | ReaderShared |
WriterShared |
Exclusive |
WriterSharedTimestamp |
|---|---|---|---|---|
ReaderShared |
לא | כן | כן | כן |
WriterShared |
כן | לא | כן | לא רלוונטי |
Exclusive |
כן | כן | כן | לא רלוונטי |
WriterSharedTimestamp |
כן | לא רלוונטי | לא רלוונטי | כן |
נעילות WriterSharedTimestamp משמשות רק כשמוסיפים שורות חדשות עם חותמת זמן כחלק מהמפתח הראשי. הנעילות WriterShared ו-Exclusive משמשות לכתיבה לתאים קיימים או להוספת שורות חדשות בלי חותמות זמן. כתוצאה מכך, WriterSharedTimestamp לא יכול להתנגש עם סוגים אחרים של נעילות, והתרחישים האלה מוצגים כלא רלוונטי בטבלה שלמעלה.
החריג היחיד הוא ReaderShared, שאפשר להחיל על שורות שלא קיימות, ולכן הוא עלול להתנגש עם WriterSharedTimestamp. לדוגמה, סריקה מלאה של טבלה נועלת את כל הטבלה, גם שורות שלא נוצרו, ולכן יכול להיות ש-ReaderShared יתנגש עם WriterSharedTimestamp.
מהו מפתח התחלה של טווח שורות?
העמודה ROW_RANGE_START_KEY מזהה את המפתח הראשי המורכב, או את המפתח הראשי ההתחלתי של טווח שורות, שיש לו התנגשויות נעילה. הסכימה הבאה משמשת להמחשת דוגמה.
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE TABLE Songs (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
TrackId INT64 NOT NULL,
SongName STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
CREATE TABLE Users (
UserId INT64 NOT NULL,
LastAccess TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
...
) PRIMARY KEY (UserId, LastAccess);
כפי שאפשר לראות בטבלה הבאה של מפתחות שורות וטווחים של מפתחות שורות, טווח מיוצג באמצעות סימן פלוס, '+', במפתח. במקרים כאלה, המפתח מייצג את מפתח ההתחלה של טווח מפתחות שבו התרחשה סתירה של נעילה.
| ROW_RANGE_START_KEY | הסבר |
|---|---|
| זמרים(2) | טבלת Singers במפתח SingerId=2 |
| albums(2,1) | טבלת אלבומים במפתח SingerId=2,AlbumId=1 |
| שירים(2,1,5) | טבלת השירים במפתח SingerId=2, AlbumId=1, TrackId=5 |
| שירים(2,1,5+) | טווח המפתחות של טבלת השירים מתחיל ב-SingerId=2,AlbumId=1,TrackId=5 |
| אלבומים(2 ומעלה) | Albums table key range starting at SingerId=2,AlbumId=1 |
| users(3, 2020-11-01 12:34:56.426426+00:00) | טבלת המשתמשים במפתח UserId=3, LastAccess=commit_timestamp |
נתונים סטטיסטיים מצטברים
SPANNER_SYS כולל גם טבלאות לאחסון נתונים מצטברים של נתונים סטטיסטיים לגבי נעילות שנאספו על ידי Spanner בתקופה מסוימת:
SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: נתונים סטטיסטיים מצטברים של כל ההמתנות לנעילה במרווחי זמן של דקה.
SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: נתונים סטטיסטיים מצטברים של כל ההמתנות לנעילה במרווחי זמן של 10 דקות.
SPANNER_SYS.LOCK_STATS_TOTAL_HOUR: נתונים סטטיסטיים מצטברים לכל ההמתנות לנעילה במרווחי זמן של שעה.
לטבלאות של נתונים סטטיסטיים מצטברים יש את המאפיינים הבאים:
כל טבלה מכילה נתונים של מרווחי זמן לא חופפים באורך שצוין בשם הטבלה.
המרווחים מבוססים על שעות. מרווחי זמן של דקה אחת מסתיימים בתחילת הדקה, מרווחי זמן של 10 דקות מסתיימים כל 10 דקות החל מתחילת השעה, ומרווחי זמן של שעה אחת מסתיימים בתחילת השעה.
לדוגמה, בשעה 11:59:30, המרווחים האחרונים שזמינים לשאילתות SQL על נתונים סטטיסטיים מצטברים של נעילות הם:
- דקה אחת: 11:58:00–11:58:59
- 10 דקות: 11:40:00–11:49:59
- שעה אחת: 10:00:00–10:59:59 AM
כל שורה מכילה נתונים סטטיסטיים של כל ההמתנות לנעילה במסד הנתונים במהלך המרווח שצוין, כשהם מצטברים יחד. לכל מרווח זמן יש רק שורה אחת.
הנתונים הסטטיסטיים שנאספים בטבלאות
SPANNER_SYS.LOCK_STATS_TOTAL_*כוללים המתנה לנעילה שלא נאספה בטבלאותSPANNER_SYS.LOCK_STATS_TOP_*ב-Spanner.חלק מהעמודות בטבלאות האלה מוצגות כמדדים ב-Cloud Monitoring. אלה המדדים שמוצגים:
- זמן ההמתנה לנעילה
מידע נוסף מופיע במאמר בנושא מדדים של Spanner.
סכמת טבלאות
| שם העמודה | סוג | תיאור |
|---|---|---|
INTERVAL_END |
TIMESTAMP |
סיום מרווח הזמן שבו התרחש העימות על הנעילה. |
TOTAL_LOCK_WAIT_SECONDS |
FLOAT64 |
הזמן הכולל של ההמתנה לנעילה בגלל התנגשויות נעילה שנרשמו עבור כל מסד הנתונים, בשניות. |
שאילתות לדוגמה
הדוגמה הבאה היא של הצהרת SQL שאפשר להשתמש בה כדי לאחזר נתונים סטטיסטיים של נעילה: אפשר להריץ את הצהרות ה-SQL האלה באמצעות ספריות הלקוח, gcloud spanner או Google Cloud המסוף.
הצגת נתוני הנעילה של המרווח הקודם של דקה אחת
השאילתה הבאה מחזירה את פרטי ההמתנה לנעילה של כל מפתח שורה עם התנגשות נעילה, כולל החלק היחסי מתוך סך התנגשויות הנעילה, במהלך מרווח הזמן האחרון של דקה אחת.
הפונקציה CAST() ממירה את השדה row_range_start_key BYTES
ל-STRING.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_minute t, spanner_sys.lock_stats_top_minute s
WHERE t.interval_end =
(SELECT MAX(interval_end)
FROM spanner_sys.lock_stats_total_minute)
AND s.interval_end = t.interval_end
ORDER BY s.lock_wait_seconds DESC;
פלט השאילתה
| row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
|---|---|---|---|---|
| Songs(2,1,1) | 2.37 | 1.76 | 0.7426 | LOCK_MODE: ReaderShared COLUMN: Singers.SingerInfo LOCK_MODE: WriterShared COLUMN: Singers.SingerInfo |
| משתמשים(3, 2020-11-01 12:34:56.426426+00:00) | 2.37 | 0.61 | 0.2573 | LOCK_MODE: ReaderShared עמודה: users._exists1 LOCK_MODE: WriterShared עמודה: users._exists1 |
1 _exists הוא שדה פנימי שמשמש לבדיקה אם שורה מסוימת קיימת או לא.
שמירת נתונים
לפחות, Spanner שומר נתונים לכל טבלה למשך תקופות הזמן הבאות:
SPANNER_SYS.LOCK_STATS_TOP_MINUTEandSPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: מרווחי זמן שכוללים את 6 השעות האחרונות.
SPANNER_SYS.LOCK_STATS_TOP_10MINUTEו-SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: מרווחי זמן שכוללים את 4 הימים הקודמים.
SPANNER_SYS.LOCK_STATS_TOP_HOURו-SPANNER_SYS.LOCK_STATS_TOTAL_HOUR: מרווחי זמן שכוללים את 30 הימים האחרונים.
פתרון בעיות של התנגשויות נעילה במסד הנתונים באמצעות נתונים סטטיסטיים של נעילות
אתם יכולים להשתמש ב-SQL או בלוח הבקרה Lock insights כדי לראות את ההתנגשויות של הנעילות במסד הנתונים.
בנושאים הבאים מוסבר איך אפשר לחקור את העימותים האלה של נעילות באמצעות קוד SQL.
בחירת תקופת זמן לבדיקה
אתם בודקים את מדדי זמן האחזור של מסד הנתונים של Spanner ומגלים תקופה שבה האפליקציה חווה זמן אחזור גבוה ושימוש גבוה במעבד. לדוגמה, הבעיה התחילה ב-12 בנובמבר 2020 בסביבות השעה 22:50.
בודקים אם זמן האחזור של אישור העסקה גדל יחד עם זמן ההמתנה לנעילה במהלך התקופה שנבחרה
העסקאות מקבלות נעילות, ולכן אם עימותי נעילה גורמים לזמני המתנה ארוכים, אמורה להיות עלייה בחביון של אישור העסקה, וגם עלייה בזמן ההמתנה לנעילה.
אחרי שבחרנו תקופת זמן להתחיל בה את הבדיקה, נצרף את נתוני העסקאות TXN_STATS_TOTAL_10MINUTE לנתוני הנעילה LOCK_STATS_TOTAL_10MINUTE מאותה תקופה כדי להבין אם העלייה בחביון הממוצע של השלמת הפעולה נובעת מהעלייה בזמן ההמתנה לנעילה.
SELECT t.interval_end, t.avg_commit_latency_seconds, l.total_lock_wait_seconds
FROM spanner_sys.txn_stats_total_10minute t
LEFT JOIN spanner_sys.lock_stats_total_10minute l
ON t.interval_end = l.interval_end
WHERE
t.interval_end >= "2020-11-12T21:50:00Z"
AND t.interval_end <= "2020-11-12T23:50:00Z"
ORDER BY interval_end;
הנתונים הבאים הם דוגמה לתוצאות שמתקבלות מהשאילתה שלנו.
| interval_end | avg_commit_latency_seconds | total_lock_wait_seconds |
|---|---|---|
| 2020-11-12 21:40:00-07:00 | 0.002 | 0.090 |
| 2020-11-12 21:50:00-07:00 | 0.003 | 0.110 |
| 2020-11-12 22:00:00-07:00 | 0.002 | 0.100 |
| 2020-11-12 22:10:00-07:00 | 0.002 | 0.080 |
| 2020-11-12 22:20:00-07:00 | 0.030 | 0.240 |
| 2020-11-12 22:30:00-07:00 | 0.034 | 0.220 |
| 2020-11-12 22:40:00-07:00 | 0.034 | 0.218 |
| 2020-11-12 22:50:00-07:00 | 3.741 | 780.193 |
| 2020-11-12 23:00:00-07:00 | 0.042 | 0.240 |
| 2020-11-12 23:10:00-07:00 | 0.038 | 0.129 |
| 2020-11-12 23:20:00-07:00 | 0.021 | 0.128 |
| 2020-11-12 23:30:00-07:00 | 0.038 | 0.231 |
התוצאות הקודמות מראות עלייה דרמטית בavg_commit_latency_seconds ובtotal_lock_wait_seconds במהלך אותה תקופה, מ2020-11-12 22:40:00 עד 2020-11-12 22:50:00, וירידה לאחר מכן. חשוב לזכור שהערך avg_commit_latency_seconds הוא הזמן הממוצע שמוקדש רק לשלב השליחה. לעומת זאת, total_lock_wait_seconds הוא זמן הנעילה המצטבר לתקופה, ולכן הזמן נראה ארוך בהרבה מזמן אישור העסקה.
אחרי שאישרנו שזמן ההמתנה לנעילה קשור קשר הדוק לעלייה בחביון הכתיבה, בשלב הבא נבדוק אילו שורות ועמודות גורמות להמתנה הארוכה.
אפשר לראות אילו מפתחות שורה ועמודות היו עם זמני המתנה ארוכים לנעילה במהלך התקופה שנבחרה
כדי לגלות אילו מפתחות שורה ועמודות חוו זמני המתנה ארוכים לנעילה במהלך התקופה שאנחנו בודקים, אנחנו שולחים שאילתה לטבלה LOCK_STAT_TOP_10MINUTE, שבה מפורטים מפתחות השורה והעמודות שתרמו הכי הרבה לזמן ההמתנה לנעילה.
הפונקציה CAST() בשאילתה הבאה ממירה את השדה row_range_start_key BYTES למחרוזת.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_10minute t, spanner_sys.lock_stats_top_10minute s
WHERE
t.interval_end = "2020-11-12T22:50:00Z" and s.interval_end = t.interval_end;
| row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
|---|---|---|---|---|
| זמרים(32) | 780.193 | 780.193 | 1 | LOCK_MODE: WriterShared COLUMN: Singers.SingerInfo LOCK_MODE: ReaderShared COLUMN: Singers.SingerInfo |
מטבלת התוצאות הזו אפשר לראות שההתנגשות התרחשה בטבלה Singersבמפתח SingerId=32. Singers.SingerInfo היא העמודה שבה התרחש העימות של הנעילה בין ReaderShared לבין WriterShared.
זהו סוג נפוץ של התנגשות שמתרחש כשטרנזקציה אחת מנסה לקרוא תא מסוים וטרנזקציה אחרת מנסה לכתוב לאותו תא. עכשיו אנחנו יודעים מה התא המדויק של הנתונים שעליו מתחרות הטרנזקציות על הנעילה, ולכן בשלב הבא נזהה את הטרנזקציות שמתחרות על הנעילות.
איך מוצאים את העסקאות שמתבצעת בהן גישה לעמודות שמעורבות בקונפליקט הנעילה
כדי לזהות את העסקאות שבהן יש השהיה משמעותית של ביצוע פעולות (commit) בפרק זמן מסוים בגלל התנגשויות נעילה, צריך להריץ שאילתה על העמודות הבאות מהטבלה SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE:
fprintread_columnswrite_constructive_columnsavg_commit_latency_seconds
צריך לסנן את העמודות הנעולות שזוהו בטבלה SPANNER_SYS.LOCK_STATS_TOP_10MINUTE:
עסקאות שקוראות עמודה כלשהי שגרמה להתנגשות נעילה כשניסו לקבל את נעילת
ReaderShared.עסקאות שכותבות לכל עמודה שגרמה להתנגשות נעילה כשניסו לרכוש נעילה מסוג
WriterShared.
SELECT
fprint,
read_columns,
write_constructive_columns,
avg_commit_latency_seconds
FROM spanner_sys.txn_stats_top_10minute t2
WHERE (
EXISTS (
SELECT * FROM t2.read_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "ReaderShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
OR
EXISTS (
SELECT * FROM t2.write_constructive_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "WriterShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
)
AND t2.interval_end ="2020-11-12T23:50:00Z"
ORDER BY avg_commit_latency_seconds DESC;
תוצאת השאילתה ממוינת לפי העמודה avg_commit_latency_seconds, כך שהעסקה עם זמן האחזור הכי גבוה של השלמת הפעולה מוצגת ראשונה.
| fprint | read_columns | write_constructive_columns | avg_commit_latency_seconds |
|---|---|---|---|
| 1866043996151916800 |
['Singers.SingerInfo', 'Singers.FirstName', 'Singers.LastName', 'Singers._exists'] |
['Singers.SingerInfo'] | 4.89 |
| 4168578515815911936 | [] | ['Singers.SingerInfo'] | 3.65 |
תוצאות השאילתה מראות ששתי טרנזקציות ניסו לגשת לעמודה Singers.SingerInfo, שהיא העמודה שהיו בה התנגשויות נעילה במהלך התקופה. אחרי שמזהים את העסקאות שגורמות להתנגשויות הנעילה, אפשר לנתח את העסקאות באמצעות טביעת האצבע שלהן, fprint, כדי לזהות בעיות פוטנציאליות שגרמו להתנגשות הנעילה.
אחרי שבודקים את העסקה עם fprint=1866043996151916800, אפשר להשתמש בעמודות read_columns ו-write_constructive_columns כדי לזהות איזה חלק מקוד האפליקציה הפעיל את העסקה. אחרי זה תוכלו לראות את ה-DML הבסיסי שלא מסנן לפי המפתח הראשי, SingerId. הפעולה הזו גרמה לסריקה מלאה של הטבלה ולנעילת הטבלה עד שהטרנזקציה אושרה.
כדי לפתור את הבעיה של נעילת הקובץ, אפשר:
- כדי לזהות את הערכים הנדרשים של
SingerId, אפשר להשתמש בעסקת קריאה בלבד. - משתמשים בעסקת קריאה-כתיבה נפרדת כדי לעדכן את השורות של הערכים הנדרשים
SingerId.
שימוש בשיטות מומלצות להפחתת התחרות על נעילה
בתרחיש לדוגמה שלנו, הצלחנו להשתמש בנתוני נעילה ובנתוני עסקאות כדי לצמצם את הבעיה לעסקה שלא השתמשה במפתח הראשי של הטבלה שלנו כשביצעה עדכונים. הצענו רעיונות לשיפור העסקה בהתאם לכך שידענו מראש את המפתחות של השורות שרצינו לעדכן או שלא ידענו אותם.
כשבודקים בעיות פוטנציאליות בפתרון, או אפילו כשמתכננים את הפתרון, כדאי לפעול לפי השיטות המומלצות האלה כדי להפחית את מספר ההתנגשויות של נעילות במסד הנתונים.
מומלץ להשתמש בעסקאות לקריאה בלבד כשאפשר, כי הן לא רוכשות נעילות.
מומלץ להימנע מסריקות מלאות של טבלאות בעסקאות קריאה-כתיבה. זה כולל כתיבת DML על סמך המפתח הראשי או הקצאת טווח מפתחות ספציפי כשמשתמשים ב-Read API.
כדי שהתקופה שבה הנתונים נעולים תהיה קצרה, צריך לבצע את השינוי כמה שיותר מהר אחרי שקוראים את הנתונים בעסקה עם הרשאת קריאה וכתיבה. טרנזקציה מסוג Read-write מבטיחה שהנתונים יישארו ללא שינוי אחרי שקוראים את הנתונים, עד שהשינוי יבוצע בהצלחה. כדי לעשות את זה, צריך לנעול את תאי הנתונים במהלך הקריאה ובמהלך השמירה של הנתונים. לכן, אם אפשר לקצר את תקופת הנעילה, הסיכוי שיהיו התנגשויות נעילה בעסקאות קטן יותר.
עדיף להשתמש בעסקאות קטנות במקום בעסקאות גדולות, או לשקול להשתמש ב-Partitioned DML לעסקאות DML ארוכות. טרנזקציה שפועלת לאורך זמן רב מקבלת נעילה למשך זמן ארוך, ולכן מומלץ לפצל טרנזקציה שמשפיעה על אלפי שורות לכמה טרנזקציות קטנות יותר שמעדכנות מאות שורות, בכל הזדמנות אפשרית.
אם לא צריך את ההבטחה שניתנת על ידי טרנזקציית קריאה-כתיבה, כדאי להימנע מקריאת נתונים בטרנזקציית קריאה-כתיבה לפני ביצוע השינוי, למשל על ידי קריאת הנתונים בטרנזקציית קריאה בלבד נפרדת. רוב העימותים של נעילות מתרחשים בגלל ההבטחה החזקה, כדי להבטיח שהנתונים יישארו ללא שינוי בין הקריאה לבין השמירה. לכן, אם העסקה לקריאה ולכתיבה לא קוראת נתונים, היא לא צריכה לנעול את התאים למשך זמן רב.
צריך לציין רק את קבוצת העמודות המינימלית שנדרשת בעסקת קריאה-כתיבה. מכיוון שנעילות ב-Spanner הן לכל תא נתונים, כשטרנזקציית קריאה-כתיבה קוראת יותר מדי עמודות, היא מקבלת
ReaderSharedנעילה על התאים האלה. זה עלול לגרום להתנגשויות נעילה כשטרנזקציות אחרות מקבלות נעילה שלWriterSharedבכתיבה לעמודות העודפות. לדוגמה, כדאי לציין קבוצה של עמודות במקום*בפעולת קריאה.צמצום הקריאות ל-API בעסקת קריאה-כתיבה. ההשהיה של קריאות ל-API עלולה לגרום למאבק על נעילה ב-Spanner, כי קריאות ל-API כפופות לעיכובים ברשת וגם לעיכובים בצד השרת. מומלץ לבצע קריאות ל-API מחוץ לעסקאות של קריאה וכתיבה, כשהדבר אפשרי. אם אתם חייבים להפעיל קריאות ל-API בתוך טרנזקציה של קריאה וכתיבה, הקפידו לעקוב אחרי זמן האחזור של הקריאות ל-API כדי לצמצם את ההשפעה על תקופת ההמתנה לקבלת נעילה.
עובדים בהתאם לשיטות המומלצות לעיצוב סכימה.
המאמרים הבאים
- מידע נוסף על כלים אחרים לבדיקת תכונות
- מידע נוסף על נתונים אחרים שמאוחסנים ב-Spanner לכל מסד נתונים זמין בטבלה information schema של מסדי הנתונים.
- מידע נוסף על שיטות מומלצות ל-SQL ב-Spanner