אינדקסים וביצועים בשרת ה- SQL

Indexes and Performance

J Steven Jones
sjones@swynk.com

מבוא

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

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

 

מה קורה במרוצת הזמן?

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

כאשר אתה בונה אינדקס לטבלה, שרת ה-SQL  מחלק את הנתונים לדפים ולחבורות (extents). בשרת SQL מגרסה 7 ומעלה,  חבורות אלו יכולות להיות משותפות למספר אובייקטים (בגרסא 6.5 ומטה חבורות יכלו להכיל אובייקט יחיד). נניח שיצרת טבלה בה גודל השורות הוא רבע מגודל העמוד. אם ברשותך 20 שורות, אז כתוצאה מכך תקבל כחמישה עמודים גרועים של נתונים.

האם הנתונים שלך מאוחסנים בחמישה דפים?

רק אם ה-FILLFACTOR הוא 100%. ה- FILLFACTOR קובע כמה אחוזים מתוך העמוד שלך ימולאו. הבה נניח FILLFACTOR של 50%. אז יהיו ברשותך כעשרה עמודים של נתונים בטבלה. דבר זה מסתבך במהירות, הבה נבחן זאת.

אם נניח שנרחיב את הדוגמא הנ"ל למשך זמן מה, ייתכן והטבלה תדרוש 100 עמודים של נתונים. עמודים אלו ידרשו (לכל הפחות) 7 חבורות אם האובייקט לא משתף חבורות. כל עמוד בתחום החבורות מקושר לעמוד אחר באמצעות מחוון (pointer). העמוד הבא בשרשרת לא בהכרח יהיה באותה החבורה. לכן כאשר אנו קוראים את העמודים, ייתכן ונצטרך להחליף לחבורה אחרת. 

הדוגמא הפשוטה ביותר לכך היא אם נניח שניקח שלושה עמודים עוקבים של נתונים בסדר הבא :            

Extent 2 Extent 1
Page n + 1 Page n
Page n + 2

אלו הם שלושה עמודים כאשר העמוד ה- n מצביע לעמוד n+1, אז לעמוד n+2 וכן הלאה. כדי לקרוא את עמודים אלו אנו קוראים חבורה מס' 1, לאחר מכן עוברים לחבורה מס' 2, ולאחר מכן מחליפים חזרה ל- 1. החלפות אלו לא מהוות בהכרח זמן I/O אבל הם נסכמות ומורידות את הביצועים. הם לא בהכרח יהוו בעיה משמעותית בשרת המקומי שלך, או אפילו שרת עמוס קלות, אולם אפליקציית רשת בעלת מאות או אלפי משתמשים עלולה לסבול מנזק מצטבר של סריקות רבות על גבי הטבלה.

למה נוצר מצב שהטבלה נראית כך?

כך הטבלה תוכננה לתפקד לאורך זמן. שרת הSQL יקצה מקום עבור כל שורה בהתבסס על המקום הפנוי הנגיש באותו זמן. כתוצאה מכך, ייתכן והעמודים לא בסדר פיסי. במקום שכל עמוד יכיל קישור לעמוד הבא ברצף. ייתכן ובדיסק הקשיח שלך יהיו פיצולים (fragment) במשך הזמן כאשר אתה מוחק ומוסיף קבצים, הקצאת הדפים לטבלה עלולה להתפצל במשך הזמן על פני חבורות כאשר הנתונים משתנים.

נשאלות השאלות:  מדוע SQL Server לא בונה מחדש את האינדקסים ? איך אנו מסירים את הפיצולים הללו ?  המשך לקרוא ...

 

הרצת  DBCC SHOWCONTIG

בגרסאות קודמות של SQL Server, היה מוטל עליך ראשית לקבל את ה-ID של האובייקט ע"י שימוש בפקודה :

select object_id('<object name>')

עבור טבלת המשתמש הרצתי :

select object_id('user')

אני מניח שמישהו התלונן על כך כיוון שב - SQL 2000 ביכולתך להשתמש בשם האובייקט באמצעות dbcc showcontig באופן הבא :

dbcc showcontig (user)

פעולה זו תפיק את הסטטיסטיקה הבאה על האינדקסים :

DBCC SHOWCONTIG scanning 'User' table...            
Table:'User' (962102468); index ID: 1, database ID: 7                     
TABLE level scan performed.         
-Pages Scanned................................: 899      
-Extents Scanned..............................: 121      
-Extent Switches..............................: 897      
-Avg. Pages per Extent........................: 7.4            
-Scan Density [Best Count:Actual Count].......: 12.58% [113:898]                  
-Logical Scan Fragmentation ..................: 99.89%            
-Extent Scan Fragmentation ...................: 80.99%            
-Avg. Bytes Free per Page.....................: 2606.5               
-Avg. Page Density (full).....................: 67.80%            

הבה נפענח את הפלט הנ"ל :

Pages Scanned   מספר הדפים שנסרקו באינדקס.

Extents scanned   מספר החבורות שנסרקו. בדוגמה הנ"ל יש לנו 121 חבורות ו- 968 דפים. כיוון שהאינדקס הוא רק 899 דפים, שי לנו מספר חבורות משותפות. דבר זה אינו בהכרח דבר רע, אך זה ממחיש את הרעיון שיש לנו פיצול קל.

Extent Switches – מספר הפעמים שהסריקה כפתה מתג מחבורה אחת לאחרת.

Average Pages/Extent – נותן את החישוב של דפים\חבורות .

Scan Density   המספר הראשון (113 בדוגמא שלנו) הוא המספר האידיאלי של שינויי חבורות אם הכל היה מקושר ברשימה רציפה. המספר השני (898 בדוגמא שלנו) הוא מספר החבורות שהועברו שהוא 1 יותר מאשר מספר המתגים (לפי ההגדרה). זוהי נקודת התבוננות נוספת על פיצול.

Logical Scan Fragmentation   "אני עדיין איני בטוח מה זה אומר. לא קיבלתי הסבר הולם לכך בשום מקום וכאן אני מביא את האינטרפרטציה שלי לנושא". מציין את אחוז הדפים באינדקס שמכילים מחוון לעמוד הבא ששונה מהמחוון לעמוד הבא שנמצא בקובץ בנתונים.

Extent Scan Fragmentation   מציין את אחוז הדפים באם העמוד הבא באינדקס לא ממוקם פיסית בסמוך לעמוד הנוכחי.

Avg. Bytes Free per Page   מציין את מספר הבתים החופשיים לעמוד (ממוצע).

Avg. Page Density -  פועל יוצא של הפרמטר הקודם.)דוגמא שלנו 2606.5 / 8096 עם עיגול כלפי מעלה).

 

אז מה בעצם כל זה אומר ?

ובכן, לי זה אומר שאני צריך לאחות (defragment )  את הטבלה.

 

איחוי אינדקסים 

בגרסאות קודמות של SQL Server היה עליך לבנות מחדש את האינדקסים ולהעביר את הנתונים לחבורות ולדפים החדשים, דבר שאמור להחזיר את הכל למקומו הפיסי ולהפחית את הפיצול.

ב- SQL Server 2000, נוספה אופציית DBCC הקרויה INDEXDEFRAG. תהליך זה משפר את הביצועים בכך שסדר הפיסי יתאם לסדר הלוגי ובכך יפחת משמעותית זמן ה- I/Oהדרוש לשרת כדי לסרוק את האינדקס.

 

סיכום 

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


  חזרה למאמרים נבחרים


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