Entity Framework והטעויות שיגרמו לכם לבעיות ביצועים

בעשור האחרון, מרבית הפיתוח מול הדטאבייסים עושה שימוש ב- ORM-ים כאלה ואחרים. אחד ה- ORM-ים הפופולריים בעולם הדוטנט, הוא Entity Framework. בפוסט הזה, אסקור טעויות נפוצות שמשליכות על ביצועים של עבודה מול ה- DB בעבודה עם ORM-ים באופן כללי, ובפרט בעבודה עם Entity Framework.
כלל הדוגמאות בפוסט מבוססות על ה- DB של Stack Overflow, בגרסה שהתאמתי עבור הקורס SQL שהקלטתי בעבר. הדוגמאות מבוססות על Entity Framework 6.2, על אף שחלקן רלוונטיות לכל סוגי ה- ORM-ים.

טעות #1 : בעיית ה- N+1

בואו נניח שאנחנו רוצים להציג את כל השאלות ב- Stack Overflow, ולצד כל שאלה – מי המשתמש שכתב אותה. נסתכל בקוד הבא:

using (var data = new Entities())

{

    foreach (var question in data.Posts.Where(k=>k.Title != null))

    {

        Console.WriteLine($"{question.Title} was asked by {question.User.DisplayName}");

    }

}

ועכשיו נשאלת השאלה – כמה שליפות SQL רצו פה מול ה- DB?להמשך קריאה

מה הבעייה עם nvarchar(max) או varchar(max)

כולנו (או לפחות, כל מי שיצר טבלה ב- DB) מכיר את הרגע שבו הוא מגיע לקבוע data type של עמודה טקסטואלית, בוחר varchar/nvarchar וצריך לקבוע את הגודל המקסימלי. האם לשים 10? 20? 100? הרי אף אחד לא יודע מה יילד יום. וכשלא יודעים מה יקרה – יש כאלה שפשוט בוחרים ללכת על המקסימום. וככה נולדות להן הרבה עמודות nvarchar(max) / varchar(max), כי הרי למה להגביל היום ולחטוף את השגיאה של string or binary data would be truncated מתישהו בעתיד?
דרך נוספת שבה עמודות כאלה נולדות – היא משימוש ב- Entity Framework Code First ושאר ה-ORM-ים. אם מגדירים string property במודל, ומייצרים ממנו באמצעות EF Code First טבלה, אז Entity Framework שואף לשמר את ההתנהגות של System.String, שאינו מוגבל באורכו, ולכן מגדיר את העמודה בתור nvarchar(max) (ניתן כמובן להשתמש ב- StringLengthAttribute כדי להגדיר אורך שונה, אבל זאת פעולה נוספת, שהרבה מפתחים לא עושים).… להמשך קריאה

SQL Server: שימוש בפונקציות COMPRESS ו- DECOMPRESS לטובת דחיסת נתונים

מזה מספר שנים, SQL Server מציע באופן מובנה יכולת של Data Compression. מדור ביכולת לדחיסת המידע בטבלאות ואינדקסים, בין אם “רגילים” (row store) או clustered / nonclusted columnstore indexes.
כאשר מדובר על דחיסה של אינדקסים “רגילים” – אנחנו יכולים לבחור בין דחיסה ברמת השורה – שהיא בעיקרה רלוונטית ל- fixed length data types, שהשמירה שלהם נעשית יותר יעילה במקום,  או ב- page level compression שמבצע בפועל row level compression של כלל השורות באותו ה- page, ומעל זה מוסיף רובד של prefix compression (שמקטין את הנפח במידה שיש ערכים מייצגים בעמודות, או לחלופין תחיליות משותפות) ו- dictionary compression (שמחליף ערכים חוזרים בהפנייה למילון שנשמר כחלק מה- metadata, ומקטין את הנפח במידה שיש חזרתיות גבוהה של ערכים ברמת ה- page).
בין אם משתמשים ב- row level compression או ב- page level compression, מופעלת גם היכולת של unicode compression שמקטינה את הנפח במידה שהעמודה מוגדרת בתור nvarchar או nchar, אולם בפועל עיקר הטקסט שבו נעשה שימוש לא באמת מתפרס על ה-2 בתים שמוקצים ב- UCS-2 לכל תו (כלומר, לאחר הדחיסה מתקבלת התנהגות שמזכירה יותר את UTF-16 במובן שלא נדרשים בפועל תמיד 2 בתים לכל תו, אלא ניתן להסתפק בתו בודד).… להמשך קריאה

DbFunctions.TruncateTime ובעיית הביצועים המוחבאת

 

לאחרונה נתקלתי בבעיית ביצועים בעת עבודה עם Entity Framework שנגרמה כתוצאה משימוש במתודה DbFunctions.TruncateTime.image_thumb7

לטובת הדוגמא, בואו נסתכל על טבלה בשם Posts במבנה כמו בתמונה מצד שמאל.
הטבלה מכילהה מס’ עמודות, ובין היתר עמודת CreationDate מסוג datetime (או datetime2, פחות רלוונטי למקרה שלנו) שכוללת התאריך והזמן של יצירת רשומה.
נניח גם שהעמודה הזאת היא ה- clustered index של הטבלה (מדובר ב- clustered index הגיוני).

המטרה שלנו –  להביא את כל השורות שנוצרו בתאריך מסויים. למשל, נרצה להביא את כל השורות שנוצרו ב- 25.06.2016 (בלי חשיבות לזמן שבה הן נוצרו).
יש כמה דרכים אפשריות לעשות את זה. אפשר לעשות שאילתה על הטווח (בין ה-25 ל-26), או שיטה אחרת, אפשרית גם כן (למרות שגם יקרה קצת יותר בביצועים),  היא לעשות CAST לעמודה ל- date (ואז מאבדים למעשה את החלק של הזמן) ולהשוות לתאריך.… להמשך קריאה

טעינת נתונים מ- SQL Server ל- Elasticsearch

תוצאת תמונה עבור ‪elasticsearch‬‏

Elasticsearch, למי שלא מכיר, הוא מנוע אינדוקס פופולרי מאד המבוסס על מנוע האינדוקס של Lucene. מדובר למעשה ב- Document DB עם דגש חזק מאד על חיפוש טקסטואלי במידע (למרות שככל שעובר הזמן מתווספים לו פיצ’רים של document db גנרי, בכלל זה גם אגרגציות וכו’).
בפוסט הזה אני אסביר איך  אפשר לדאוג לזרימת נתונים שוטפת מ- SQL Server ל- Elasticsearch.

למה שנרצה דבר כזה?

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

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