דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. ארכיון code613m
  4. מניפולציות על קובץ XML בעת ייבוא לSQL

מניפולציות על קובץ XML בעת ייבוא לSQL

מתוזמן נעוץ נעול הועבר ארכיון code613m
16 פוסטים 4 כותבים 1.2k צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • A מנותק
    A מנותק
    avr416
    כתב ב נערך לאחרונה על ידי
    #7

    @דוד ל.ט.

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

    צודק לגמרי! הייתה לי שם טעות בקוד, ושכחתי לעשות SUBSTRING לעמודה אחרת..
    תוך 3 שניות הוא המיר לי את כל הקבצים לתוך הטבלה!!
    @דוד ל.ט.

    ההבדל הענק בין הLink2Sql לבין הSQL-SERVER טעון פירוט רקע של כמה דברים. ברור שהכנסה בEF איטית מSQL כי כל הבדיקות והאילוצים מבוצעים פעמיים, אבל עדיין זה לא הסבר לפער כה עצום.

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

    SELECT CONVERT(XML, BulkColumn) AS BulkColumn
    FROM OPENROWSET(BULK 'C:\Users\Avraham\Downloads\השמטות הרמבם\äÖÄêàÜ äÿÄüì\003420123-0094.xml', SINGLE_BLOB) AS x;
    

    ואח"כ אני רץ בלולאה על התאים הללו וממיר אותם לטבלה, דבר שלוקח 3 שניות ל94 קבצי XML.
    מאידך, יש לי את קוד הC# הבא, שעושה את אותה עבודה אך לוקח לו 7 דקות!!

    private async Task<bool> addXmlPageToDB(string folder, int bookID)
            {
                var files = Directory.GetFiles(folder, "*.xml");
                await Task.Run(() =>
                {
                    foreach (var file in files)
                    {
                        XElement xml = XElement.Load(new StreamReader(file));
                        var page = from pa in xml.Descendants("Page")
                                   select pa.Attribute("ID").Value;
                       
                        var numPage = page.First().Substring(1);
    
                        var printSpace = from ps in xml.Descendants("PrintSpace")
                                         select ps;
                        var textBlocks = from tb in printSpace.Descendants("TextBlock")
                                         select tb;
                        foreach (var block in textBlocks)
                        {
                            int tbID = int.Parse(block.Attribute("ID").Value.Substring(6));
                            var textLines = from tl in block.Descendants("TextLine")
                                            select tl;
                            foreach (var line in textLines)
                            {
                                int tlID = int.Parse(line.Attribute("ID").Value.Substring(6));
                                var strings = from str in line.Descendants("String")
                                              select str;
                                foreach (var st in strings)
                                {
                                    int strID = int.Parse(st.Attribute("ID").Value.Substring(6));
                                    var word = new word()
                                    {
                                        PageID = numPage,
                                        textBlockID1 = tbID,
                                        textLineID1 = tlID,
                                        stringID1 = strID,
                                        CONTENT = st.Attribute("CONTENT").Value.Trim(),
                                        HEIGHT = st.Attribute("HEIGHT").Value,
                                        WIDTH = st.Attribute("WIDTH").Value,
                                        HPOS = st.Attribute("HPOS").Value,
                                        VPOS = st.Attribute("VPOS").Value,
                                        CC = st.Attribute("CC").Value,
                                        WC = decimal.Parse(st.Attribute("WC").Value),
                                        BookID = bookID.ToString()
                                    };
                                    db.words.Add(word);
                                }
                            }
                        }
                    }
                });           
                db.SaveChanges();
                return true;
            }
    

    פורסם במקור בפורום CODE613 ב27/08/2016 22:26 (+03:00)

    תגובה 1 תגובה אחרונה
    0
    • dovidD מנותק
      dovidD מנותק
      dovid ניהול
      כתב ב נערך לאחרונה על ידי
      #8

      בEF ככל שכמות הרשומות פר קונטקסט ו/או פר קומיט (שמירה) עולה, אז המהירות יורדת.
      אם מדובר ב200,000 שורות זה הסבר מניח את הדעת.

      אני אכן הייתי דבק בC# מחמת שאינני מבין/שולט בSQL בכלל ובפרט בקוד שהבאת. אבל מצורפים פה שיקולי עצלות שגויים עם נכונים...
      תבדוק בלי הEF, כלומר תבטל להערה את שורה 46. לדעתי זה ייקח זמן דומה לSQK SERVER. אם כן הפוקוס הוא הEF.
      אתה יכול לעשות שתי דברים למהר את הEF:

      1. לבטל את AutoDetectChangesEnabled + ValidateOnSaveEnabled.
      2. לשמור + להחריב (Dispose) את הdb ולהציב בו מופע חדש כל X רשומות.
        זה המקור שלי: http://stackoverflow.com/a/5942176/1271037
      • http://stackoverflow.com/a/15662102/1271037

      אגב הTask מחזיר bool אבל הוא האותה מידה יכול לא להחזיר כלום (Task ללא פרמטר גנרי) ולא השורה האחרונה (53).

      ובשולי הדברים כל הכבוד...

      פורסם במקור בפורום CODE613 ב28/08/2016 01:10 (+03:00)

      • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
      • בכל נושא אפשר ליצור קשר dovid@tchumim.com
      תגובה 1 תגובה אחרונה
      1
      • א מנותק
        א מנותק
        ארכיטקט
        כתב ב נערך לאחרונה על ידי
        #9

        אוקי, אז בשורה 53 למעשה הוא נתקע (ולא בשורה 46 כמו שדוד אמר) מה שקורה ה EF מריץ שאילתה נפרדת עבור כל אינסרט שעשית, כלומר כמידת צעדי הלולאה, הוא עושה לולאה משלו כל רשומה רצה בשאילתה נפרדת. אתה יכול לראות את זה בפרופיילר.
        השאילתות לא רצות במקביל, אלא כל אחת ממתינה לתשובה מהדטה בייס. ולא זו בלבד אלא שאחרי שהשאילתה בוצעה הוא עוד שואב משם מידע כדי לקבל את ה ID וכדומה.

        פורסם במקור בפורום CODE613 ב28/08/2016 10:25 (+03:00)

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

        תגובה 1 תגובה אחרונה
        2
        • A מנותק
          A מנותק
          avr416
          כתב ב נערך לאחרונה על ידי
          #10

          תודה רבה דוד, אכן הקוד עצמו ללא האנטיטי רץ ב00.3 שניות על 94 קבצי XML.
          לאחר ששמעתי בעצתך ועשיתי את 2 הדברים שהמלצת (גם שינוי הקונפיגורציה של EF וגם חיסול המופע של האנטיטי ויצירתו מחדש) המהירות שופרה פלאים!!
          כאשר הגדרתי את המונה ל100 הקוד לקח 17 שניות, כשהגדרתי ל1000 לקח לו בין 1.2 ל 1.7 (ניסיתי כמה פעמים). וכשהגדרתי ל10000 וכן ל5000 לקח לו באזור ה1.6 שניות!! (קודם לקח לו 7 דקות!!).
          כמו כן שמתי לב, שאם אני מריץ את הקוד הזה פעמיים, אז בפעם השניה זה לוקח שניה פחות! (כלומר 0.7 שניות סה"כ) כנראה מכיון שהוא כבר מחזיק את החיבור לדטה בייס פתוח או משהו כזה.
          הנה התוספת לקוד (הבאתי רק את הלולאה הפנימית):

          foreach (var st in strings)
                                      {
                                          int strID = int.Parse(st.Attribute("ID").Value.Substring(6));
                                          var word = new word()
                                          {
                                              PageID = numPage,
                                              textBlockID1 = tbID,
                                              textLineID1 = tlID,
                                              stringID1 = strID,
                                              CONTENT = st.Attribute("CONTENT").Value.Trim(),
                                              HEIGHT = st.Attribute("HEIGHT").Value,
                                              WIDTH = st.Attribute("WIDTH").Value,
                                              HPOS = st.Attribute("HPOS").Value,
                                              VPOS = st.Attribute("VPOS").Value,
                                              CC = st.Attribute("CC").Value,
                                              WC = decimal.Parse(st.Attribute("WC").Value),
                                              BookID = bookID.ToString()
                                          };
          
                                          counter++;
                                          if (counter < 1000)
                                              db.words.Add(word);
                                          else
                                          {
                                              db.words.Add(word);
                                              db.SaveChanges();
                                              db.Dispose();
                                              db = new Model1();
                                              counter = 0;
                                          }                               
                                      }
                                  }
          

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

          ארכיטקט - תודה על ההסבר מה עומד מאחורי ההתנהגות של הEF.

          פורסם במקור בפורום CODE613 ב28/08/2016 12:02 (+03:00)

          תגובה 1 תגובה אחרונה
          0
          • A מנותק
            A מנותק
            avr416
            כתב ב נערך לאחרונה על ידי
            #11

            מה שמוזר הוא שהדטה בייס עצמו נשאר ריק...
            רק אם אני מוסיף בסוף הקוד פעם נוספת - db.SaveChanges() אז אכן הנתונים נשמרים בדטהבייס, ואז אכן לוקח לקוד לרוץ כ15 שניות.
            זה ממש מוזר, הרי אני קורא לפונקציה הזו לאחר כל 1000 איטרציות, אז אני מבין שאם לבסוף הכנסתי פחות מ1000 אז כל האחרונים לא ישמרו, אבל מדוע כל ה33,000 האחרים לא נשמרים?! (כלומר בשורה 54 אני קורא לפונקציה הזו, אז למה אם שורה 64 תמחק לא יכנסו לדטהבייס שום נתונים????)
            הנה הקוד במלואו:

            private async Task<bool> addXmlPageToDB(string folder, int bookID)
                    {
                        var files = Directory.GetFiles(folder, "*.xml");
                        await Task.Run(() =>
                        {
                            foreach (var file in files)
                            {
                                XElement xml = XElement.Load(new StreamReader(file));
                                var page = from pa in xml.Descendants("Page")
                                           select pa.Attribute("ID").Value;
                               
                                var numPage = page.First().Substring(1);
            
                                var printSpace = from ps in xml.Descendants("PrintSpace")
                                                 select ps;
                                var textBlocks = from tb in printSpace.Descendants("TextBlock")
                                                 select tb;
                                int counter = 0;
                                foreach (var block in textBlocks)
                                {
                                    int tbID = int.Parse(block.Attribute("ID").Value.Substring(6));
                                    var textLines = from tl in block.Descendants("TextLine")
                                                    select tl;
                                    foreach (var line in textLines)
                                    {
                                        int tlID = int.Parse(line.Attribute("ID").Value.Substring(6));
                                        var strings = from str in line.Descendants("String")
                                                      select str;
                                        foreach (var st in strings)
                                        {
                                            int strID = int.Parse(st.Attribute("ID").Value.Substring(6));
                                            var word = new word()
                                            {
                                                PageID = numPage,
                                                textBlockID1 = tbID,
                                                textLineID1 = tlID,
                                                stringID1 = strID,
                                                CONTENT = st.Attribute("CONTENT").Value.Trim(),
                                                HEIGHT = st.Attribute("HEIGHT").Value,
                                                WIDTH = st.Attribute("WIDTH").Value,
                                                HPOS = st.Attribute("HPOS").Value,
                                                VPOS = st.Attribute("VPOS").Value,
                                                CC = st.Attribute("CC").Value,
                                                WC = decimal.Parse(st.Attribute("WC").Value),
                                                BookID = bookID.ToString()
                                            };
            
                                            counter++;
                                            if (counter < 1000)
                                                db.words.Add(word);
                                            else
                                            {
                                                db.words.Add(word);                                    
                                                db.SaveChanges();
                                                db.Dispose();
                                                db = new Model1();
                                                counter = 0;
                                            }                               
                                        }
                                    }
                                }
                            }
                        });           
                        db.SaveChanges();
                        return true;
                    }
            

            פורסם במקור בפורום CODE613 ב28/08/2016 12:34 (+03:00)

            תגובה 1 תגובה אחרונה
            0
            • dovidD מנותק
              dovidD מנותק
              dovid ניהול
              כתב ב נערך לאחרונה על ידי
              #12

              ממש מופלא. שמת נקודת עצירה על הSaveChanges?

              אגב לקוד פשוט יותר תוכל לכתוב ככה:

              db.words.Add(word);
              
              if (++counter % 1000 == 0)
              {
                  db.SaveChanges();
                  db.Dispose();
                  db = new Model1();
              }
              

              זה מחליף את 48 ואילך.

              פורסם במקור בפורום CODE613 ב28/08/2016 18:35 (+03:00)

              • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
              • בכל נושא אפשר ליצור קשר dovid@tchumim.com
              תגובה 1 תגובה אחרונה
              3
              • א מנותק
                א מנותק
                ארכיטקט
                כתב ב נערך לאחרונה על ידי
                #13

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

                פורסם במקור בפורום CODE613 ב28/08/2016 19:15 (+03:00)

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

                תגובה 1 תגובה אחרונה
                1
                • A מנותק
                  A מנותק
                  avr416
                  כתב ב נערך לאחרונה על ידי
                  #14

                  טוב, אז זו הייתה טעות טיפשית שלי :?
                  איתחלתי את המונה בתוך הלולאה הראשונה, כך שהוא התאפס כל הזמן לפני שהגיע לאלף איטרציות..
                  אגב, עכשיו אני רואה שאם אני לא משתמש בכלל במונה ולא מאפס את הEF אז זה לוקח לו הכי מהר (אחרי ששיניתי את ההגדרות של הקונפיגורציה כמובן..) (ל33,000 שורות 16 שניות).
                  אם המונה פועל על מאה אז זה כמעט אותו זמן, אם הוא על 1000 לוקח לו 32 שניות, אם הוא על 10000 לוקח לו יותר מדקה..
                  אז נראה שבכלל זה מיותר לאפס אותו ולאתחל אותו מחדש.

                  פורסם במקור בפורום CODE613 ב28/08/2016 22:43 (+03:00)

                  תגובה 1 תגובה אחרונה
                  1
                  • dovidD מנותק
                    dovidD מנותק
                    dovid ניהול
                    כתב ב נערך לאחרונה על ידי
                    #15

                    @avr416

                    אגב, עכשיו אני רואה שאם אני לא משתמש בכלל במונה ולא מאפס את הEF אז זה לוקח לו הכי מהר (אחרי ששיניתי את ההגדרות של הקונפיגורציה כמובן..) (ל33,000 שורות 16 שניות).
                    אם המונה פועל על מאה אז זה כמעט אותו זמן, אם הוא על 1000 לוקח לו 32 שניות, אם הוא על 10000 לוקח לו יותר מדקה..
                    אז נראה שבכלל זה מיותר לאפס אותו ולאתחל אותו מחדש.

                    תודה רבה רבה על הפרטים החשובים!
                    מאוד מעניין, זה לבטח שינוי בEF כי זה בבירור לא היה ככה בעבר.

                    פורסם במקור בפורום CODE613 ב31/08/2016 17:44 (+03:00)

                    • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
                    • בכל נושא אפשר ליצור קשר dovid@tchumim.com
                    תגובה 1 תגובה אחרונה
                    1
                    • A מנותק
                      A מנותק
                      avr416
                      כתב ב נערך לאחרונה על ידי
                      #16

                      עכשיו ראיתי פוסט יפה בעברית בנושא:

                      יש לו שם עוד כמה פוסטים בנושא sql server.

                      פורסם במקור בפורום CODE613 ב13/12/2016 21:22 (+02:00)

                      תגובה 1 תגובה אחרונה
                      4

                      בא תתחבר לדף היומי!
                      • התחברות

                      • אין לך חשבון עדיין? הרשמה

                      • התחברו או הירשמו כדי לחפש.
                      • פוסט ראשון
                        פוסט אחרון
                      0
                      • דף הבית
                      • קטגוריות
                      • פוסטים אחרונים
                      • משתמשים
                      • חיפוש
                      • חוקי הפורום