שליפה אקראית של שורות מטבלה בגרסת 2012

24/02/2012

אין תגובות

לפני כשבועיים כתבתי פוסט לגבי שליפה אקראית של שורות מטבלה, ולמרבה הצער היו שתי אפשרויות שלכל אחת חסרונות משלה:
1. שימוש במיון בעזרת New_ID שמחזיר את התוצאה המבוקשת אבל כרוך במיון של טבלה שעלולה להיות גדולה מאוד.
2. שימוש בכלים מובנים של SQL Server ש”עולים” פחות אבל מחזירים מספר שורות שלא ניתן לצפות מראש במדוייק.
גרסת 2012 שעומדת להשתחרר ב-07/03/2012 כוללת את אופציית ה-Paging שיכולה לסייע לנו במקרה זה: נשלוף 20 שורות (או כל מספר אחר) החל מנקודה אקראית בטבלה. המחיר יהיה פניה לטבלת המערכת sys.sysindexes כדי לברר כמה שורות יש בטבלה, ו-Scan לטבלה ממנה שולפים עד לנקודה בה נשלוף רצף של 20 שורות.
לא פתרון מושלם – נקבל 20 שורות רצופות שעלולות להיות דומות או מאותו תאריך – אבל אופצייה מעניינת נוספת שכדאי להתחשב בה.
ניצור טבלה בת כ-230,000 שורות לצורך ההדגמה:

Use tempdb;

Go

 

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

Go

 

Select  *

Into    Messages

From    sys.messages;

וכעת לקוד:

Declare  @Frm Int,

         @Cnt Int=20;

 

Select   Top (1) @Frm=1+Rand()*(rowcnt-@Cnt) From sys.sysindexes Where id=Object_ID('Messages');

 

Print    @Frm;

 

Select   *

From     Messages

Order By GetDate()

Offset   @Frm Rows Fetch Next @Cnt Rows Only;

image

ממספר השורות החסרנו 20 כדי שלא נתחיל לשלוף מנקודה בה כבר לא יניו עוד 20 שורות,

את המספר כפלמו במספר אקראי בין 0 ל-1,

והוספנו 1 למקרה שהמספר האקראי יהיה 0.

פקודת ה-Print באמצע היא לצורך בקרה וניתן לוותר עליה.

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

Select  *

From    Messages M

Order By GetDate()

Offset  Cast((Select 1+Rand()*(rowcnt-20) From sys.sysindexes Where id=Object_ID('Messages')) As Int) Rows Fetch Next 20 Rows Only;

image

במקרה זה חישוב נקודת ההתחלה (offset) מתבצע בשאילתת משנה.

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

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

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

כתיבת תגובה

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