שפת טיפול בנתונים עם חלוקה למחיצות (partitioned DML) מיועדת לסוגים הבאים של עדכונים ומחיקות בכמות גדולה:
- ניקוי תקופתי ו-garbage collection. לדוגמה, מחיקה של שורות ישנות או הגדרת עמודות ל-
NULL. - מילוי חוזר של עמודות חדשות בערכי ברירת מחדל. לדוגמה, אפשר להשתמש בהצהרת
UPDATEכדי להגדיר את הערך של עמודה חדשה ל-False, אם הערך הנוכחי הואNULL.
חלוקה למחיצות של פקודות DML לא מתאימה לעיבוד עסקאות בקנה מידה קטן. אם רוצים להריץ הצהרה על כמה שורות, צריך להשתמש בפקודות DML טרנזקציוניות עם מפתחות ראשיים שניתנים לזיהוי. מידע נוסף מופיע במאמר שימוש ב-DML.
אם אתם צריכים לבצע כמות גדולה של כתיבות עיוורות, אבל לא נדרשת טרנזקציה אטומית, אתם יכולים לבצע שינויים בכמות גדולה בטבלאות Spanner באמצעות כתיבה באצווה. מידע נוסף מופיע במאמר שינוי נתונים באמצעות כתיבה באצווה.
אתם יכולים לקבל תובנות לגבי שאילתות DML פעילות עם חלוקה למחיצות וההתקדמות שלהן מטבלאות הנתונים הסטטיסטיים במסד הנתונים של Spanner. מידע נוסף זמין במאמר בנושא נתונים סטטיסטיים של פקודות DML פעילות עם חלוקה למחיצות.
DML ו-DML עם חלוקה למחיצות
Spanner תומך בשני מצבי ביצוע של משפטי DML:
DML, שמתאים לעיבוד עסקאות. מידע נוסף מופיע במאמר בנושא שימוש ב-DML.
DML עם חלוקה למחיצות, שמאפשר לבצע פעולות רחבות היקף בכל מסד הנתונים עם השפעה מינימלית על עיבוד עסקאות בו-זמני. כדי לעשות זאת, המערכת מחלקת את מרחב המפתחות ומריצה את ההצהרה על מחיצות בעסקאות נפרדות בהיקף קטן יותר. מידע נוסף מפורט במאמר בנושא שימוש ב-DML מחולק למחיצות.
בטבלה הבאה מפורטים כמה מההבדלים בין שני מצבי ההפעלה.
| DML | Partitioned DML |
|---|---|
יכול להיות שהשורות שלא תואמות לסעיף WHERE יהיו נעולות. |
רק שורות שתואמות לסעיף WHERE יינעלו. |
| יש מגבלות על גודל העסקה. | מערכת Spanner מטפלת במגבלות על עסקאות ובמגבלות על מספר העסקאות המקבילות. |
| הצהרות לא צריכות להיות אידמפוטנטיות. | פקודת DML צריכה להיות אידמפוטנטית כדי להבטיח תוצאות עקביות. |
| עסקה יכולה לכלול כמה הצהרות DML ו-SQL. | טרנזקציה עם חלוקה למחיצות יכולה לכלול רק פקודת DML אחת. |
| אין הגבלות על המורכבות של ההצהרות. | ההצהרות צריכות להיות ניתנות לחלוקה מלאה. |
| אתם יוצרים עסקאות של קריאה וכתיבה בקוד הלקוח. | מערכת Spanner יוצרת את העסקאות. |
ניתן לחלוקה למחיצות ואידמפוטנטי
כשמריצים פקודת DML עם חלוקה למחיצות, לשורות במחיצה אחת אין גישה לשורות במחיצות אחרות, ואי אפשר לבחור איך Spanner יוצר את המחיצות. חלוקה למחיצות מבטיחה יכולת הרחבה, אבל היא גם אומרת שמשפטי DML מחולקים למחיצות חייבים להיות ניתנים לחלוקה מלאה למחיצות. כלומר, אפשר לבטא את פקודת ה-DML עם החלוקה למחיצות כאיחוד של קבוצת משפטים, כאשר כל משפט ניגש לשורה אחת בטבלה וכל משפט לא ניגש לטבלאות אחרות. לדוגמה, אי אפשר לבצע חלוקה למחיצות של פקודת DML שמתבצעת בה גישה לכמה טבלאות או שמתבצע בה self-join. אם אי אפשר לחלק את משפט ה-DML, Spanner מחזיר את השגיאה BadUsage.
אפשר לחלק את פקודות ה-DML האלה באופן מלא, כי כל פקודה יכולה לחול על שורה אחת בטבלה:
UPDATE Singers SET LastName = NULL WHERE LastName = '';
DELETE FROM Albums WHERE MarketingBudget > 10000;
אי אפשר לחלק את פקודת ה-DML הזו באופן מלא, כי היא ניגשת לכמה טבלאות:
# Not fully partitionable
DELETE FROM Singers WHERE
SingerId NOT IN (SELECT SingerId FROM Concerts);
יכול להיות ש-Spanner יבצע פקודת DML עם חלוקה למחיצות כמה פעמים על חלק מהמחיצות בגלל ניסיונות חוזרים ברמת הרשת. כתוצאה מכך, יכול להיות שהוראה תופעל יותר מפעם אחת בשורה. לכן, ההצהרה צריכה להיות אידמפוטנטית כדי להניב תוצאות עקביות. הצהרה היא אידמפוטנטית אם ביצוע שלה כמה פעמים בשורה אחת מוביל לאותה תוצאה.
פקודת ה-DML הזו היא אידמפוטנטית:
UPDATE Singers SET MarketingBudget = 1000 WHERE true;
פקודת ה-DML הזו היא לא אידמפוטנטית:
UPDATE Singers SET MarketingBudget = 1.5 * MarketingBudget WHERE true;
מחיקת שורות מטבלאות ראשיות עם טבלאות משניות שנוספו להן אינדקסים
כשמשתמשים בפקודת DML עם חלוקה למחיצות כדי למחוק שורות בטבלת אב, יכול להיות שהפעולה תיכשל עם השגיאה: The transaction contains too many
mutations. המצב הזה קורה אם בטבלת ההורה יש טבלאות צאצא משולבות שמכילות אינדקס גלובלי. מוטציות בשורות של טבלת הצאצא עצמה לא נספרות במגבלת המוטציות של העסקה.
עם זאת, מוטציות מקבילות לרשומות האינדקס נספרות. אם מושפעים מספר גדול של רשומות באינדקס של טבלת צאצא, יכול להיות שהעסקה תחרוג ממגבלת השינויים.
כדי להימנע מהשגיאה הזו, צריך למחוק את השורות בשתי הצהרות נפרדות של DML עם חלוקה למחיצות:
- מריצים מחיקה מחולקת במחיצות בטבלאות הצאצא.
- מריצים מחיקה עם חלוקה למחיצות בטבלת האב.
התהליך הזה, שכולל שני שלבים, עוזר לשמור על מספר המוטציות במסגרת המגבלות המותרות לכל עסקה. אפשרות אחרת היא להסיר את האינדקס הגלובלי בטבלת הצאצא לפני שמוחקים את השורות בטבלת ההורה.
נעילת שורות
מערכת Spanner מקבלת נעילה רק אם שורה היא מועמדת לעדכון או למחיקה. ההתנהגות הזו שונה מהפעלה של DML, שעלולה לנעול שורות לקריאה שלא תואמות לסעיף WHERE.
הרצה ועסקאות
ההחלטה אם פקודת DML מחולקת למחיצות או לא תלויה בשיטה של ספריית הלקוח שבוחרים להרצה. כל ספריית לקוח מספקת שיטות נפרדות להרצת DML ולהרצת DML עם חלוקה למחיצות.
אפשר להריץ רק פקודת DML אחת עם חלוקה למחיצות בקריאה לשיטה של ספריית הלקוח.
Spanner לא מחיל את משפטי ה-DML עם החלוקה למחיצות באופן אטומי על כל הטבלה. עם זאת, ב-Spanner מוחלות הצהרות DML עם חלוקה למחיצות באופן אטומי בכל מחיצה.
חלוקה למחיצות של DML לא תומכת בביצוע (commit) או בהחזרה למצב קודם (rollback). Spanner מבצע ומחיל את פקודת ה-DML באופן מיידי.
- אם מבטלים את הפעולה, Spanner מבטל את המחיצות הפועלות ולא מתחיל את שאר המחיצות. Spanner לא מבטל מחיצות שכבר בוצעו.
- אם ביצוע ההצהרה גורם לשגיאה, הביצוע נפסק בכל המחיצות ו-Spanner מחזיר את השגיאה הזו עבור כל הפעולה. דוגמאות לשגיאות: הפרות של אילוצים של סוגי נתונים, הפרות של
UNIQUE INDEXוהפרות שלON DELETE NO ACTION. בהתאם לנקודת הזמן שבה הביצוע נכשל, יכול להיות שההצהרה הופעלה בהצלחה בחלק מהמחיצות, ויכול להיות שהיא לא הופעלה אף פעם במחיצות אחרות.
אם פקודת ה-DML עם החלוקה למחיצות מצליחה, Spanner מריץ את הפקודה לפחות פעם אחת מול כל מחיצה של טווח מפתחות.
מספר השורות ששונו
הוראת DML עם חלוקה למחיצות מחזירה רף תחתון של מספר השורות ששונו. יכול להיות שהמספר לא יהיה מדויק, כי אין ערובה לכך ש-Spanner יספור את כל השורות ששונו.
הגבלות על עסקאות
Spanner יוצר את המחיצות והטרנזקציות שהוא צריך כדי להריץ פקודת DML מחולקת. חלות הגבלות על עסקאות או הגבלות על מספר העסקאות המקבילות, אבל Spanner מנסה לשמור על העסקאות במסגרת ההגבלות.
ב-Spanner אפשר להריץ עד 20,000 הצהרות DML מחולקות בו-זמנית לכל מסד נתונים.
תכונות שלא נתמכות
חלק מהתכונות של DML עם חלוקה למחיצות לא נתמכות ב-Spanner:
- אין תמיכה ב-
INSERT. - מסוףGoogle Cloud : אי אפשר להפעיל הצהרות DML עם חלוקה למחיצות במסוףGoogle Cloud .Google Cloud
- תוכניות שאילתה ופרופילים: Google Cloud CLI וספריות הלקוח לא תומכים בתוכניות שאילתה ובפרופילים.
- שאילתות משנה שקוראות מטבלה אחרת, או משורה אחרת באותה טבלה.
בתרחישים מורכבים, כמו העברת טבלה או טרנספורמציות שדורשות הצטרפות בין טבלאות, כדאי להשתמש במחבר Dataflow.
שיטות מומלצות
כדי לשפר את הביצועים של הצהרות DML עם חלוקה למחיצות, כדאי לפעול לפי השיטות המומלצות הבאות:
- הימנעות מריבוי פעולות בו-זמניות: הפעלה בו-זמנית של מספר גדול של הצהרות DML עם חלוקה למחיצות (לדוגמה, יותר מ-100) עלולה להוביל למאבק על נעילה בטבלאות מערכת פנימיות, ולפגוע בביצועים. במקום להריץ מספר גדול של הצהרות בו-זמניות, כדאי להשתמש בהצהרת DML אחת עם חלוקה למחיצות.
- שימוש ב-
PDML_MAX_PARALLELISM: כדי להגדיל את התפוקה של פקודת DML מחולקת אחת, במיוחד בטבלאות עם הרבה פיצולים, מגדירים ערך גבוה יותר לרמז להצהרהPDML_MAX_PARALLELISM. כך אפשר להשתמש ביותר מקביליות באופן פנימי בהצהרה אחת. הגדרה של ערך גבוה יותר ל-PDML_MAX_PARALLELISMמובילה לשימוש רב יותר במחשוב, ולכן כדאי לנסות לאזן בין השימוש במחשוב לבין מהירות העיבוד המוגברת. - מאפשרים ל-Spanner לטפל בחלוקה למחיצות: לא מומלץ לבצע שרדינג של הנתונים באופן ידני (לדוגמה, באמצעות טווחי מפתחות ראשיים) ולהפעיל הצהרות DML מחולקות נפרדות בכל שארד. ה-DML המחולק למחיצות נועד לחלק את העבודה ביעילות בין כל המחיצות בטבלה. פיצול מותאם אישית של נתונים (sharding) לרוב מגדיל את התקורה ויכול להחמיר את התחרות על משאבים.
- הסבר על היקף החלוקה למחיצות: פעולות DML מחולקות למחיצות ומבוצעות במקביל בכל הפיצולים במסד הנתונים כולו, ולא רק בפיצולים שמכילים נתונים של הטבלה שמשנים. כלומר, במסדי נתונים עם מספר גדול של פיצולים, יכול להיות שיהיו תקורה גם אם טבלת היעד קטנה או שהנתונים ששונו הם מקומיים. יכול להיות ש-DML עם חלוקה למחיצות לא יהיה הבחירה היעילה ביותר לשינוי חלק קטן מאוד במסד נתונים גדול.
- כדאי לשקול חלופות למחיקות קטנות ותכופות: בתרחישי שימוש שכוללים מחיקות תכופות של מספר קטן של שורות ידועות, שימוש בהצהרות DML בתוך טרנזקציות או ב-BatchWrite API עשוי להניב ביצועים טובים יותר ותקורה נמוכה יותר מאשר שימוש ב-DML עם חלוקה למחיצות.
דוגמאות
בדוגמה הבאה של קוד מתבצע עדכון של העמודה MarketingBudget בטבלה Albums.
C++
משתמשים בפונקציה ExecutePartitionedDml() כדי להפעיל פקודת DML עם חלוקה למחיצות.
C#
משתמשים ב-ExecutePartitionedUpdateAsync() method כדי להריץ פקודת DML עם חלוקה למחיצות.
Go
משתמשים ב-PartitionedUpdate() method כדי להריץ פקודת DML עם חלוקה למחיצות.
Java
משתמשים ב-executePartitionedUpdate() method כדי להריץ פקודת DML עם חלוקה למחיצות.
Node.js
משתמשים ב-runPartitionedUpdate() method כדי להריץ פקודת DML עם חלוקה למחיצות.
PHP
משתמשים ב-executePartitionedUpdate() method כדי להריץ פקודת DML עם חלוקה למחיצות.
Python
משתמשים ב-execute_partitioned_dml() method כדי להריץ פקודת DML עם חלוקה למחיצות.
Ruby
משתמשים ב-execute_partitioned_update() method כדי להריץ פקודת DML עם חלוקה למחיצות.
בדוגמה הבאה של הקוד מוצגת מחיקה של שורות מהטבלה Singers, על סמך העמודה SingerId.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
מה השלב הבא?
כדי לקרוא על ההבדלים בין DML לבין מוטציות, אפשר לעיין במאמר השוואה בין DML לבין מוטציות
מומלץ להשתמש במחבר Dataflow לתרחישים אחרים של שינוי נתונים.