none
למה הוספת שורות ל SQL CE מתצבע בצורה איטית? RRS feed

  • שאלה

  • שלום לכולם,

    אני משתמשת במסד נתונים של SQL SERVER COMPACT באמצעות ENTITY FRAMEWORK , כאשר אני מוסיפה בערך 200 שורות למסד הנתונים -> ההוספה מתבצעת בצורה איטית, צריך לחכות בין 10 ל20 שניות,  ניסתי גם להוסיף את השורות באמצעות שאילתה עם שימוש בSqlCeCommand ,  אך זה לא מהיר יותר, איך אפשר להוסיף שורות בצורה יותר מהירה? ( לפי מה שהבנתי שימוש בפרוצדורה (stored procuder)יכול לבצע את זה בצורה מהירה, הבעיה היא שהSQL SERVER CE לא תומך בשימוש בפרוצדורות)

    תודה!

    יום רביעי 27 מאי 2015 17:46

כל התגובות

  • ערב טוב,

    1. אני ממליץ בעתיד, להקפיץ הודעות אם אתה לא מקבל תגובה אחרי שבוע-שבועיים, גם אם ההודעה ניראית בתחילת הפורום.

    ההודעות בפורמים של MSDN לא מופרדות לפי פורומים אלא משותפות לכל הפורומים. כך למשל תוכך להיכנס לקישור הבא:
    https://social.msdn.microsoft.com/Forums/he-IL/home?forum=azurehe%2Cnethe%2Csqlgetstarted%2CVisualCsharpil%2CMsdnmod%2Cmoderatorshe%2Csqlhe%2Csqlexpress%2Ctransactsql%2Ccsharpgeneral%2Cwebdevhe
    ותוכל לראות הודעות ממספר פורומים שונים בעברית בהם אני לוקח חלק.

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

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

    2. נעבור לשאלה :-)

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

    2.1 אם רוצים מיטוב עבודה אז אני ממלית לא לעבוד עם ORM! מערכות ORM כמו EF מועדו לשפר מהירות וקלות פיתוח ולא מקצועיות ומיטוב תוצאה! לעולם לא יהיה ORM שיכול לבצע את מה שיכול לבצע ידנית איש מקצוע שיש לו את הידע המתאים.

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

       string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
            + "FROM Person "
            + "WHERE Discriminator = 'Student' "
            + "GROUP BY EnrollmentDate";
        IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

    2.3 אני מאוד ממליץ לעבור על הקישור הבא:
    Performance Considerations for Entity Framework
    https://msdn.microsoft.com/en-us/data/hh949853.aspx

    2.4 מהירות הכנסת נתונים לטבלה יכולה להיות קשורה לגורמים רבים כגון:

    * מהירות IO (כתיבה וקריאה לדיסק)
    * מיטוב השאילתה עצמה (ראה הערה 2.2)
    * אופן ביצוע השאילתה (האם כל פעולה מ 200 הפעולות מבוצעעת בנפרד בזו אחרי זו או שמבצעים הכנסה של 200 נתונים יחד)
    * אופי הנתונים עצמם
    * מבנה מסד הנתונים (אינדקסים וטריגרים למשל יטכלים מאוד להאט פעולות של הכנסה או עדכון נתונים)
    * כתיבה ללוג השרת יכולה להאט פםעולות בצורה קיצונית. אנא חפש חומר על BULK INSERT
    * כמובן כמו תמיד... מה מצב המשאבים של המכונה ומה רץ במקביל

    כאמור לא סיפקת לנו מידע מספקי כדי להבין היכן הבעיה ספציפית :-)

    2.5 מעל הכל ולכן השארתי לסיום נמצא העובדה שהרבה פעמים הבעיה נמצא בתכנון של הקוד והביצוע ב EF. מאוד נפוץ שמפתחים מבצעים פעולות נפרדות במקום פעולה אחת. צריך להכניס את כל הנתונים בשאיתה אחת ולא בלולאה למשל.

    לסיכום:

    אנא צרף יותר מדיע כמו למשל קוד דרכו אתה מכניס את הנתונים, מבנה מסד הנתונים שלך, דוגמה של נתונים שאתה מנסה להכניס וכו'


    signature   Ronen Ariely
     [Personal Site]    [Blog]    [Facebook]

    יום שלישי 02 יוני 2015 15:44
    מנחה דיון
  • היי

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

    כמ"כ תודה שהפנת את תשומת ליבי בנוגע להודעות בפורום MSDN.

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

    אני משתמשת במסד הנתונים של Sql server compact 3.5 , הגישה שלי למסד הנתנים היא באמצעות Entity Framework , לאחר יצירת הקישור למסד הנתונים ( לENTITY) נוצר קובץ App.config המגדיר בין היתר את הנתיב למסד הנתונים, במקרה שלי המסד נתונים נמצא בתוך תקיית בBIN של הפרויקט, הקוד להלן:

     <connectionStrings>
        <add name="SchoolDBEntities" connectionString="metadata=res://*/Models.SchoolDB.csdl|res://*/Models.SchoolDB.ssdl|res://*/Models.SchoolDB.msl;provider=System.Data.SqlServerCe.3.5;provider connection string=&quot;Data Source=SchoolDB.sdf&quot;" providerName="System.Data.EntityClient"/>
      </connectionStrings>


    האוביקט שאני יוצרת בקוד המקיר את מסד הנתונים( אוביקט הEntity) מוגדר בקוד כך:

    public SchoolDBEntities SchooleEntities;

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

    הסבר הקוד : יצירת אוביקט מסוג טבלת Report,  טבלת ProfesionOFGrades  היא טבלת רבים לרבים, המקושרת לטבלת Report עם foreign key, בלחיצת כפתור התוכנה תוסיף דו"ח לכל התלמידים , מס' הרשומות שנוסיף ל REPRORT כמס' התלמידים , ומס' הרשומות שנוסיף ל  ProfesionOFGrades  כמס' המקצועות (לכל היותר 20). לדוג, אם מוסיפים ל 10  תלמדים , יתווספו  200 שורות לטבלת ProfesionOFGrades  , למה ההוספה מתבצעת בצורה איטית?

    להלן הקוד:

      public SchoolDBEntities SchooleEntities=new SchoolDBEntities();
    
    StudentOC=new List<Student>(SchooleEntities.Students);
    ProfesionOC=new List<Profesion>(SchooleEntities.Profesions);
      foreach (var item in StudentOC)
                   {
                 
                       Report r = new Report()
                       {
                           code = Manager.GetInstance.SchooleEntities.Reports.NextId(f => f.code),
                           student = item.code,
                           date=year,
                                        };
                       
                       Manager.GetInstance.SchooleEntities.Reports.AddObject(r);
      
                     foreach (var itemGrade in ProfesionOC)
                     {
    
                      
                         ProfesionOfGrade p = new ProfesionOfGrade()
                    {
                        code = Manager.GetInstance.SchooleEntities.ProfesionOfGrades.NextId(f => f.code),
                                           report = r.code,
                                         grade = 0
                    };
                         Manager.GetInstance.SchooleEntities.ProfesionOfGrades.AddObject(p);
                         Manager.GetInstance.SchooleEntities.SaveChanges();
                         
                     } 
                   }
               }


    כמ"כ ניסיתי להוסיף את הרשומות לטבלאות באמצעות קישור ישיר ללא EF , אך הבעיה לא נפתרה, ועדיין זה מתבצע בצורה איטית

    הקוד להלן:

     SqlCeConnection conn = new SqlCeConnection("Data Source=SchoolDB.sdf");
                        
            int       code = Manager.GetInstance.SchooleEntities.Reports.NextId(f => f.code);
                 int      student = item.code;
                       SqlCeCommand cmd0 = new SqlCeCommand();
                       cmd0.Connection = conn;
                       cmd0.CommandText = "insert into Report(code,student,date) values(@code, @student,@date)";
    
                       cmd0.Parameters.Add("@code", SqlDbType.Int).Value = Convert.ToInt32(code);
                       cmd0.Parameters.Add("@student", SqlDbType.Int).Value = Convert.ToInt32(student);
                                       cmd0.Parameters.Add("@date", SqlDbType.NVarChar).Value = date;
    
                       cmd0.CommandType = CommandType.Text;
                       conn.Open();
                       cmd0.ExecuteNonQuery();
                       conn.Close();

    יום רביעי 03 יוני 2015 21:15
  • את מבצעת בדיוק את הבעיה שניחשתי וכתבתי עליה למעלה

    את מכנהיסה כל נתון בנפרד. הבעיה בפקודה

    cmd0.CommandText = "insert into Report(code,student,date) values(@code, @student,@date)";

    את צריכה להכניס את כל הנתנים ביחד

    זה כמו ההבדל בין להריץ 200 פעמים את השאילתה לבין להריץ פעם אחת שאילתה שמכניסה הכל ביחד.

    תעברי על הקישור הבא, לגבי עבודה עם Bulk insert באמצעות EF
    https://efbulkinsert.codeplex.com/


    signature   Ronen Ariely
     [Personal Site]    [Blog]    [Facebook]

    • הוצע כתשובה על-ידי tetitu יום שלישי 09 יוני 2015 06:42
    יום חמישי 04 יוני 2015 07:06
    מנחה דיון
  • היי,

    ניסתי לעבוד עם BULK INSERT באמצעות EF אבל זה מעיף לי שגיאה על ה  ctx.BulkInsert(entities)- ניסית לפתור את הבעיה ולא הצלחתי,

    אך מצאתי אפשרות אחרת: (sqlcebulkcopy.codeplex.com/) SqlCeBulkCopy - מאוד קל לביצוע (לא באמצעות EF) , כמו שכתבת, האיטיות נבעה מהרצת שאילתה כמה פעמים, ולא פעם אחת,  וכאן אפשר לשלוח LIST שלם ולבצע זאת בפעם אחת,

     using (SqlCeBulkCopy bc = new SqlCeBulkCopy(conn))
                               {
    
                                   bc.DestinationTableName = "ProfesionOfGrade";
                                   bc.WriteToServer(listp);
                               }

    תודה רבה!

    המשך יום טוב!






    • נערך על-ידי lea_b יום שלישי 09 יוני 2015 15:23
    • הוצע כתשובה על-ידי Guy GlantserMVP, Moderator יום רביעי 08 יולי 2015 05:28
    יום שלישי 09 יוני 2015 15:21
  • בכיף :-)

    אנא זיכרי לסגגור את השרשור על ידי סימון התשובות, והצבעה על הודעות מועילות


    signature   Ronen Ariely
     [Personal Site]    [Blog]    [Facebook]

    יום שלישי 09 יוני 2015 18:05
    מנחה דיון