מיגרציות במסד נתונים מוסברות - איך משנים סכימה בלי לשבור הכל¶
בשלב מסוים בכל פרויקט אמיתי, מגיע הרגע שבו צריך להוסיף עמודה לטבלה, לשנות סוג נתונים, או לפצל טבלה לשתיים. השאלה היא איך עושים את זה בלי לאבד נתונים ובלי להפיל את המערכת בדרך. זו בדיוק הבעיה שמיגרציות פותרות.
מה זו בכלל מיגרציה¶
מיגרציה היא קובץ קוד שמתאר שינוי ספציפי במבנה מסד הנתונים - הוספת עמודה, יצירת טבלה, שינוי אינדקס - יחד עם הדרך לבטל את השינוי הזה אם צריך (rollback). במקום לשנות את הסכימה ידנית דרך כלי ניהול, כותבים את השינוי כקוד, שומרים אותו בבקרת גרסאות יחד עם שאר הקוד, ומריצים אותו דרך כלי ייעודי שדואג להריץ אותו בסדר הנכון ולעקוב מה כבר הופעל ומה לא.
למה לא פשוט לשנות ידנית בממשק הניהול¶
זו נראית כמו דרך קלה ומהירה, ובאמת - לפרויקט אישי קטן זה יכול להספיק. אבל בכל צוות, ובכל מערכת שרצה בכמה סביבות (פיתוח, בדיקות, פרודקשן), השינוי הידני הופך למקור לבעיות אמיתיות:
- אין תיעוד של מה השתנה ומתי. אחרי חצי שנה, אף אחד לא זוכר למה בכלל הוסיפו עמודה מסוימת.
- קשה לשחזר את אותו מבנה בסביבה אחרת. אם הפיתוח והפרודקשן לא זהים, מתחילים להיתקל בבאגים שקורים רק באחת הסביבות.
- אין דרך בטוחה לבטל שינוי. אם שינוי ידני יצר בעיה, צריך לזכור בדיוק מה עשיתם כדי לתקן חזרה.
מיגרציות פותרות את כל זה - כל שינוי מתועד, ניתן לשחזור באופן זהה בכל סביבה, וניתן לביטול אם משהו משתבש.
איך זה עובד בפועל¶
כלי מיגרציה שומר טבלה מיוחדת במסד הנתונים שרושמת אילו מיגרציות כבר רצו. כשמריצים מיגרציה חדשה, הכלי בודק אילו קבצים עוד לא רצו על הסביבה הספציפית הזו, ומריץ אותם לפי הסדר. זה מבטיח שגם אם עובדים בצוות של כמה מפתחים, כל אחד יכול להריץ את אותן מיגרציות בדיוק על הסביבה שלו, ולהגיע לאותו מבנה סכימה בדיוק.
רוב הפריימוורקים המודרניים כוללים כלי מיגרציה מובנה, וגם קיימים כלים עצמאיים שעובדים עם כל שפת תכנות ומסד נתונים.
הבעיה האמיתית - מיגרציה על טבלה גדולה בפרודקשן¶
זה המקום שבו מיגרציות הופכות ממשימה שגרתית לאתגר הנדסי אמיתי. הוספת עמודה לטבלה עם כמה שורות בודדות היא פעולה מיידית. אבל הוספת עמודה לטבלה עם מיליוני שורות בפרודקשן, במיוחד אם יש לה ערך ברירת מחדל שצריך לחשב לכל שורה, יכולה לנעול את הטבלה לזמן ארוך ולהפיל את המערכת עבור כל המשתמשים שמנסים לגשת אליה באותו זמן.
הפתרון לבעיה הזו הוא לפרק מיגרציה מסוכנת לכמה שלבים בטוחים:
- מוסיפים את העמודה החדשה כללית (nullable), בלי ערך ברירת מחדל שדורש חישוב מיידי על כל השורות. זו פעולה מהירה כמעט תמיד.
- ממלאים את הערכים בהדרגה, ברקע, בקבוצות קטנות (batches), כדי לא להעמיס על מסד הנתונים בבת אחת.
- רק בסוף, אחרי שכל השורות מלאות, מוסיפים את האילוץ שהעמודה חייבת להיות לא ריקה (NOT NULL), אם בכלל צריך.
זה נראה מסורבל יותר משינוי אחד פשוט, אבל זה ההבדל בין מיגרציה שעוברת בשקט לבין מיגרציה שמפילה את השירות בשעת שיא.
עוד עיקרון חשוב - תאימות לאחור¶
בכל מערכת שרצה בייצור עם דיפלוי הדרגתי, יש רגע שבו הקוד הישן והחדש רצים במקביל. מיגרציה שמוחקת עמודה שהקוד הישן עדיין משתמש בה יכולה לשבור את הגרסה הישנה לפני שכל השרתים עברו לגרסה החדשה. לכן, בפרויקטים בקנה מידה גדול נהוג לפרק שינויים הרסניים (כמו מחיקת עמודה) לכמה דיפלוי נפרדים - קודם מפסיקים להשתמש בעמודה בקוד, ורק בדיפלוי מאוחר יותר מוחקים אותה בפועל מהסכימה.
איפה לומדים לתכנן מיגרציות נכון¶
התיאוריה של מיגרציות פשוטה, אבל לדעת לתכנן שינוי בטוח לטבלה גדולה בפרודקשן זה משהו שנרכש מניסיון. בקורס צד שרת אנחנו עובדים עם מיגרציות בתוך פרויקט אמיתי, כולל הדרך הנכונה לשנות סכימה בלי לסכן את המערכת.
מתכננים מיגרציה על טבלה גדולה ולא בטוחים איך לגשת לזה בבטחה? שאלו בדיסקורד לפני שאתם מריצים אותה בפרודקשן, לא אחרי.
לסיכום¶
מיגרציות הופכות שינויי סכימה מפעולה ידנית ומסוכנת לתהליך מתועד, חוזר, וניתן לביטול. לפרויקט קטן זה נוחות, אבל לצוות ולמערכת שרצה בייצור זה הכרחי. תלמדו לפרק מיגרציות מסוכנות לשלבים בטוחים, ותחשבו תמיד על מה קורה כשקוד ישן וחדש רצים זה לצד זה בו זמנית.