התנייה במספר השורות

15/06/2012

אין תגובות

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

Use tempdb;

Go

 

If Object_ID('Messages') Is Not Null Drop Table Messages;

Go

 

Select  *

Into    Messages

From    sys.messages;

 

Select  *

From    Messages;

clip_image002

האפשרות המיידית העולה בדעתנו היא לבדוק ישירות כמה שורות יש בטבלה בעזרת Count,

אך במחשבה שניה- למה להתאמץ אם כל המידע שמור בטבלאות המערכת?

Select  Count(1) rowcnt

From    Messages;

 

Select  Max(rowcnt) rowcnt

From    sys.sysindexes

Where   object_name(id)='Messages';

clip_image004

אותה תוצאה, אבל מה המחיר?

clip_image006

צפוי, ברור וחד משמעי: לבצע Scan על טבלה שלמה עולה הרבה יותר מאשר לשלוף מידע זמין שחושב מראש.

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

Select  Count(1) rowcnt

From    Messages

Where   message_id=21;

 

Select  Count(1)

From    (Select Top 2 1 [Cnt]

        From    Messages

        Where   message_id=21) T;

clip_image008

clip_image010

כמובן- למה לבצע Scan מלא על הטבלה? עדיף לעצור לאחר שני הראשונים- כבר יש לנו כל המידע הרלוונטי, ובמחיר נמוך בהרבה.

אם מישהו עדיין מתעקש לבדוק כמה שורות יש בכפוף לתנאי ולא רק אם מספרן גדול או שווה ל-2; הוא יוכל לשפר את השליפה אם ישתמש ב-Filtered Index:

Create Index PK_V_Messages On Messages(message_id,language_id) Where message_id=21;

ומבחינת הביצועים (אותן שליפות כמו קודם):

clip_image012

שתי האפשרויות אופטימליות במקרה זה (בפוטופיניש יש יתרון מזערי לשליפה השניה ששולפת רק 2 שורות ראשונות), וכדאי לשים לב ששתיהן עושות שימוש באינדקס..

ולסיום אופציה מעניינת נוספת שכדאי לשקול- ניצור Indexed View עם השליפה המפולטרת, ואז יעמדו בפנינו שתי אפשרויות- לבצע Select Count על ה-View, או לבדוק מה מספר השורות שלו ב-sysindexes הנ"ל (נבטל קודם את האינדקס הנ"ל כדי שהמערכת לא תבחר להשתמש בו ותטה בכך את התוצאות):

Drop index Messages.PK_Messages;

Go

 

Create View V_Messages With Schemabinding As

Select  message_id,

        language_id

From    dbo.Messages

Where   message_id=21;

Go

 

Create Unique Clustered Index PK_V_Messages On V_Messages(message_id,language_id);

GO

וכעת נשווה:

Select  Max(rowcnt) rowcnt

From    sys.sysindexes

Where   object_name(id)='V_Messages';

 

Select  Count(1) rowcnt

From    V_Messages (NoExpand);

clip_image014

השליפה מה-View יותר יעילה למרבה הפלא מפניה לטבלת המערכת, ומבחינה אבסולוטית עולה כמו שליפה דומה עם Filtered Index; אבל חייבה אותי במקרה זה בשימוש ב-NoExpend Hint למרות שמדובר ב-Enterprise Edition.

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

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *