הבלוג של גרי רשף

09/09/2011

באגים של מיקרוסופט?

Filed under: Uncategorized — גרי רשף @ 09:20

רבים מכירים את הסיטואציה בה מפתח – לרוב בתחילת דרכו – מנסה להריץ קוד, לא מצליח ומקבל הודעת שגיאה או תוצאות שגויות, ולאחר שמשתכנע שעשה הכל נכון, מגיע למסקנה הבלתי נמנעת שזה באג של מיקרוסופט..
זה קצת מזכיר לי את אלו שנושאים עיניים לשמיים בלילה, רואים איזה אור זז, ולאחר שפוסלים את האפשרות שזה מטוס או מסוק או טיל באליסטי עם ראש נפץ גרעיני; הם מגיעים לכלל מסקנה שזה עב"מ ועליו חייזרים ירוקים ממאדים.
מעבר לכשל הלוגי שבלזהות כלי טיס בתור עב"מ, זה פתרון קל מדי ומאוד לא סביר.
לא סתם ציינתי שמדובר בדרך כלל בבעלי מקצוע בראשית דרכם: במשך השנים אנחנו לומדים לא ליפול למלכודות ולאתר את מקור התקלה בזריזות על סמך הסימפטומים; ומבינים שבאגים של מיקרוסופט יש בכל מיני מקרי קצה ולא במרכז הבמה..
כל זה אינו אלא הקדמה לשני מקרים שקרו לי לאחרונה בהם התמודדתי עם שליפות SQL שהחזירו לי תוצאות לא הגיוניות, ולמרות שיש לי נסיון רב בלפתור בעיות כאלו- בזבזתי עליהן מספר ימים בנסיונות נואשים להבין מה הסיבה לכך שהמערכת פועלת באופן בלתי הגיוני בעליל.
אני מתאר לעצמי שכעת כשאתאר את הבעיות ואת פתרונן, קל מאוד לומר בדיעבד "נו זה ברור, איך לא חשבת על זה ישר?..", אבל ככה זה- הרבה יותר קל להתמודד עם בעיות כשכבר יודעים מה הפתרון..

אירוע 1: הלקוח דיווח ששליפה מסויימת אינה מחזירה תוצאות נכונות או עקביות. השליפה נראתה בערך כך-

Select  MyCol,

*

From MyView1

Join MyView2

On

Where

Order By ..;

כשהרצתי אותה במקביל כמו שהיא אך ללא הכוכבית * שב-Select – העמודה השמאלית החזירה תוצאות שונות.

לאחר שווידאתי ששתי השליפות זהות למעט הכוכבית, ולאחר שנברתי מעט ב-views אליהם היא פנתה ושהם עצמם פנו ל-Views אחרים בשני דטבייסים שונים – עמדתי מול שוקת שבורה: מה בעצם אני מחפש? הרי לא אמצא באחד מה-Views איזה גמד רשע עם מצנפת לראשו שמשבש בזדון את הנתונים.. הן לו היה מתפרסם אתגר נושא פרסים לכתיבת שליפה שמחזירה תוצאות שונות בעמודה הראשונה – תלוי אם יש אחריה שימוש בכוכבית – לא הייתה לי כל שיטה לעשות זאת..

אולי יש בעיה בתצוגה של ה-SSMS? הפניתי את הפלטים לטבלאות זמניות ווידאתי שהם שונים ולא מדבר באחיזת עיניים.

DBA אחר שהתגייס לעזור לי, כל מה שהוא מצא היה שיש הבדלים ב-Collations של שני הדטבייסים, אבל זה לא מסביר שום דבר: אם זה משבש משהו, זה אמור לשבש בשניהם.

אולי הנתונים משתנים כל הזמן ובחלקיק השניה שבין הרצת שתי השליפות קרה משהו? בדקנו ורק אני מחובר לשרת.

המנתח של המערכת שאינו איש SQL מובהק אך מי יודע –אולי הוא רואה דברים שאני עיוור להם – חשד שהנתונים בטבלאות משובשים כי זו סביבת בדיקות, אלא שזה אינו תירוץ: אם הם משובשים, הפלטים אמורים להיות משובשים באותו אופן!

לכל מי שהיה מוכן לעזור הראיתי איך אני מעתיק את הקוד הראשון על ידי "העתק והדבק", מוחק רק את הכוכבית, מריץ ומקבל תוצאות שונות בעמודת MyCol, ומשכנע אותו שזה לא יכול להיות.

עצות ורעיונות לא היו חסרים, וככל שהתרחב מעגל נותני העצות – כך היה לי פחות זמן להמשיך ולנסות בעצמי (אם כי ממילא ניסיתי כבר כל מה שהעליתי בדעתי), שלא לדבר על כך שהעצות התחילו להיות מוזרות ותמוהות (נסה לכתוב פרוצדורה ב-#C ולפנות דרך שרת חיצוני לאחר שניטרלת את ה-Firewall תוך הפעלת Trace..) ונאלצתי להסביר באריכות מדוע אינן מתאימות במקרה זה.

אכן שמחה וששון מסביב, וכבודי נרמס בראש חוצות: הרי אני הוא זה שאליו פונים בשעת הדחק כדי לפתור בעיות TSQL..

לבסוף נמצא המקור לבעייה- עמוק בתחתית אחד מה-Views המשניים הופיעה שליפה מעין זו שנועדה להחזיר את התיאור האחרון של כל MyID (ממספרים בסדר יורד של תאריכים ולוקחים את הראשון):

Select  *
From    (Select *,
                Row_Number() Over(Partition By MyID Order By MyDate Desc) Mispar
        From …) T
Where   Mispar=1;

מתברר שהצירוף של MyID & MyDate אינו יחודי (Unique) ולכן היו מספר תאריכים שהיו "ראשונים" (בסדר יורד) והמערכת בכל פעם לקחה אחד אחר.. למה היא לקחה בכל פעם אחד אחר (הרי אין מנגנון אקראי למקרה של רשומות זהות במיון) – אינני יודע ולא הצלחתי לשחזר מצב כזה, אבל שגיאה לוגית אין כאן, והתוצאות השונות של שתי השליפות היו נכונות – כל אחת כשלעצמה – בהתאם למה שהוגדר.

אירוע 2: הפעם מדובר בשליפה מתוך View שהעמודה האחרונה שלו מחזירה רק Nulls למרות שציפיתי שיהיו בה ערכים.

אולי בריצה הלילית לא התעדכנה הטבלה אליה פונה ה-View? בדקתי והיא כן התעדכנה.

אולי הטבלה התעדכנה אבל העמודה המסויימת לא? בדקתי את נתוני המקור וגם העמודה אמורה הייתה להתעדכן.

ניגשתי להגדרה של ה-View, וביצעתי את השליפה בעזרת ה-Select שב-View: הפעם כן הופיעו ערכים בעמודה המדוברת.

הכיצד? הפעם זה לא לקח לי כמה ימים כמו במקרה הראשון, ושימוש ממוקד בקללות וגידופים (שלא כאן המקום להזכירם אך הם כלי עזר רב עוצמה בפתרון בעיות בתחום המחשבים) עשה את שלו, ולאחר שריפרשתי את ה-View בעזרת SP_RefreshView הבעייה נפתרה:

Exec SP_RefreshView MyView;
Go

למי שלא יודע- כשמשנים מבנה של טבלה (הוספה או גריעה של עמודות) זה עלול לשבש את ה-Views שפונים אליה בעזרת כוכבית * (במקום לציין במפורש את שמות העמודות כפי שמומלץ), ויש לרפרש אותם בעזרת פרוצדורת המערכת הנ"ל. אכן- זמן מה לפני כן הוספנו עמודה, זו לא פעם ראשונה שאני נופל בגלל זה, ולכן הפעם זה לא לקח הרבה זמן..

מסקנה: אין חכם כבעל ניסיון – בעיקר ביחס לבעיה שנפתרה (כאמור- הרבה יותר קל להתמודד עם בעיות לאחר שכבר יודעים מה הפתרון), אבל גם ביחס לבעיות עתידיות..

בכלל- כשאני פותר בזריזות מפתיעה בעיות שאחרים הסתבכו איתן במשך שעות וכעת הם נבוכים מהתקלה המטופשת שהפילה אותם בפח, אני מעודד ומנחם אותם- לא הייתי מצליח לפתור את זה כל כך מהר לולא אני עצמי נתקעתי עם משהו דומה בעבר, והשעות הרבות שבזבזתי אז – היו תשלום ראוי לתמורה שאני מקבל כיום.

מודעות פרסומת

להגיב »

עדיין אין תגובות.

RSS feed for comments on this post. TrackBack URI

כתיבת תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s

יצירה של אתר חינמי או בלוג ב־WordPress.com.

%d בלוגרים אהבו את זה: