איך להתמודד עם Filegroup שמסרב להימחק?
הכל התחיל בכך שרצינו למחוק Filegroup מסוים. בהתאם לתרגולת, העברנו את הטבלאות שהיו עליו ל- Filegroup אחר על ידי מחיקה ויצירה מחדש של ה-clustered indexes שלהן. (אם יש להם גם non-clustered index גם אותם יש להעביר באותה צורה ל- Filegroup החדש). אחרי שהקובץ שהיה בו התרוקן לחלוטין, מחקנו את ה-Filegroup באמצעות הפקודה:
ALTER DATABASE MyDB remove FILE oldFile;
ולאחר מכן ניסינו למחוק את ה- Filegroup באמצעות הפקודה:
ALTER DATABASE MyDB REMOVE FILEGROUP OldFilgroup
להפתעתנו קבלנו הודעת שגיאה שאומרת שה- Filegroup אינו ריק, ולכן לא ניתן למחוק אותו.
בשלב זה בוצעה בדיקה מהירה ב- properties של בסיס הנתונים, במסך של ה-files, ושם ראינו שאין אף קובץ על ה- Filegroup העקשן. נו, אם אין שום קובץ, מה בעצם יכול לחיות על ה Filegroup?
השאלה הועברה לידידנו ד"ר גוגל, שהציע לבדוק אם אין partition schema שמצביע על ה- Filegroup האמור, אולם גם שם לא מצאנו את הפתרון. למרות שלא היה על ה- file group שום קובץ ואף partition schema לא הצביעה עליו, SQL Server המשיך להתעקש שעדין יש על ה- file group חיים שאסור להשמיד.
את הפתרון, יש להודות, גיליתי במקרה. מכירים את הקטע הזה שמיצית את הפתרונות המוכרים לך (ולגוגל) ואתה מנסה לחשוב "מה בעצם פספסתי כאן?" זה בערך היה השלב שבו בדקתי ב- sys.tables אם יש בה נתונים שיכולים לעזור לי. נכון, זה אדיוטי, לא ניתן לאכלס טבלה בנתונים אם היא ממוקמת על filegroupשאינו מכיל קבצים, והסבירות שקיימת טבלה שכזאת היא אפסית (אלא אם כן מדובר ב- DBA מאוד מבולבל). יתרה מזאת, עמודת ה- data_space_id המציינת את ה-Filegroup של כל הטבלאות (והאינדקסים) בבסיס הנתונים, קיימת כבר ב-sys.indexes, כך שלכאורה sys.tables לא אמורה להיות רלוונטית לבעיה בה נתקלתי.
אז זהו, שזה לא מדוייק! את עיני צדו שתי עמודות שהכילו בשמם את הבטוי data_space_id. הראשונה filestream_data_space_id והשניה היתהlob_data_space_id. מהעמודה הראשונה התעלמתי באלגנטיות, מאחר שבבסיס הנתונים המדובר לא הופעל filestream, אבל בדיקה מהירה בעמודה השניה גילתה לי שיש טבלה שה- lob_data_space_id שלה מצביע על אותו Filegroup עקשן.
זה נראה לי זמן מתאים לתחקיר קטן, להבין על מה מדובר. טבלה יכולה להחזיק שני סוגים של מידע: in row data ו- lob. In row data זה המידע שמאוחסן ברמת הרשומה של הטבלה ע"פ מגבלות גודל (עד 8000 תווים). כאשר יוצרים clustered index המידע הזה יאורגן וימוין בהתאם לאינדקס. למעשה מדובר על הרוב המוחלט של טיפוסי העמודות חוץ מה-LOB. ה-LOB הינו מידע בינארי או טקטסטואלי גדול מאוד: varchar(max), nvarchar(max), varbinary(max), xml נחשבים-LOB. ע"פ הגדרת ברירת המחדל, מידע מטיפוסים כאלה, אם הוא חורג מאורך השורה, נשמר מחוץ לרשומה ומופנה ע"י מצביע (Pointer) ברשומה. (לקריא נוספת על נושא in-row-data קראו כאן).
לאותה טבלה שתפסה את ה- Filegroup אכן היתה עמודת xml עם נתונים חורגים באורכם. בבדיקה במאפייני הטבלה ראיתי שה-Filegroup ששימש לשמירת textהוא אותו Filegroup בעייתי. עכשיו כבר הכל היה ברור. הטבלה, שבמקורה היתה על ה- Filegroup שיועד למחיקה, הוזזה באמצעות rebuild ל- clustered indexאל Filegroup אחר. הבעיה היתה שההערך בעמודה lob_data_space_id של טבלה זאת המשיך להצביע על ה- Filegroup הישן. את המאפיין הזה לא ניתן לשנות, ולכן היה צורך למחוק את הטבלה וליצור אותה מחדש. רק לאחר מכן אפשר היה סופסוף למחוק את ה- Filegroup העקשן.
לסיכום, לא מספיק להזיז טבלאות ולמחוק קבצים מ- Filegroup על מנת למחוק אותו. כדי לעשות זאת, יש לוודא שאין partition scheme אשר מצביעה עליו ושאין אף טבלה המצביעה עליו בעמודות filestream_data_space_id או lob_data_space_id שב- sys.tables.