none
פתיחת connection בsql server דרך .net console application RRS feed

  • שאלה

  • בוקר טוב!

    אני מפתחת .net שעובד עם sql server DB.

    לאחרונה יש לי בעיות של פתיחה של מדי הרבה connections, הייתי שמחה אם משהו יוכל להפנות אותי למידע בנושא.

    כרגע הגישה שלי לDB נעשת באמצעות entity framework וADO.net.

    איך שקראתי במאמרים שמצאתי, כל הרעיון של הconnection pooling ממומש לי ב2 המקרים האילו.

    ובכל זאת בגישה דרך ado.net אני לא עושה פתיחה וסגירה לconnection אחרי כל שאילתה שאני מפעילה לDB.

    הפונקציה שלי לקבלת מידע נראה ככה:

    try
                {
                    using (SqlConnection con = getOpenConnection())
                    {
                        SqlCommand command = new SqlCommand(null, con);
    
                        // Create and prepare an SQL statement.
                        command.CommandText = cmd;
                        SqlParameter[] parameters = GenerateSQLParam(p);
                        if (parameters != null)
                            foreach (SqlParameter param in parameters)
                            {
                                command.Parameters.Add(param);
                            }
    
                        SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
    
                        DataTable dt = new DataTable();
    
    
                        dataAdapter.Fill(dt);
                    
                        return dt;
    
                      
                    }
    
                    
                }
                catch (Exception ex)
                {
                    LogUtil.WriteToLogFile(ex.Message, "DBUtilErr");
                    return null;
                }

    למיטב הבנתי, היא לא פותחת וסוגרת connection כל פעם (כמובן שבconnectionstring שלי לא מופיע לא להשתמש בconnection pool).

    כשאני מסתכלת בsql server profiler אני רואה כל הזמן פתיחה וסגירה של connections.

    1. האם aduit login וaduit logout אכן אומר פתיחה וסגירה?

    אם כן, מה אני עושה לא נכון?

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

    האם זה קשור להרצת האפליקציה?
    האם זה קשור לזה שכל פעם נפתח connection חדש?
    יש לי אפשרות לפתור את זה? או פשוט לגשת בצורה יותר איטית? (למשל לעשות sleep בין השאילתות)

    תודה!!!

    שרה.

    יום חמישי 31 יולי 2014 07:03

תשובות

  • בוקר טוב שרה,

    >> "pooled"

    - זה בדיוק מה שציפיתי :-) זה אומר שלא מדובר על חיבור חדש אלא שימוש ב POOL

    >> "בכל אופן כמעט כל פעולה שלי פותחת בaduit login ונסגרת בaduit logout, האם זה תקין?"

    - את צריכה להבין שכל נושא ניהול ה POOL נעשה על ידי האפליציה שלך ולא על שרת ה SQL. למעשה כל השאלה הזו לא קשורה לפורום SQL והיתה צריכה להגיע בפורום C# למשל. תעהרי על הבלוג הבא לעומק (הוא מאוד גם למי שכבר יש לו את הבסיס):

    כמו שכתבתי קודם aduit login וכן aduit logout הם אירועים שיוצגו גם בהתחברות ל POOL וגם בחיבור חדש לשרת. זה פשוט ניטור לא נכון וזו ההתנהגות. אם זה "תקין" או לא זה כבר את צריכה להחליט אבל זו ההתנהגות "הנורמלית" בכל מקרה :-)

    >> לגבי הקוד שלך, הנה כמה נקודות שאולי יעזרו:

    יש חשיבות לסוג היישום כשמדברים על SESSION או CONNECTION וכו, למשל באפליקציה אינטרנטית המעבר לעמוד חדש יוצר בברירת המחדל סגירה של המשאבים של העמוד הקודם (ה IIS מנהל חלק ניכר מהפעולות). אי לנו מידע על סוג האפליקציה שלך...

    - אני אישית מאוד לא אוהב את הגישה של הסתמכות על בלוקים של TRY/CATCH או שימוש בצורות של "אם החיבור לא קיים אז תפתח אותו". בדרך כלל (כמובן לא תמיד), זה מצביע על כך שאת לא יודעת מה קורה באפליקציה וצריכה לבדוק או להסתיר את מה שקורה.

    חיבורים למסד הנתונים דרך ADO.NET אכן בברירת המחדל נכנסים ל POOL. הוראה של פתיחת חיבור חדש לא תמיד יוצרת חיבור חדש אלא מתלבשת על חיבור קיים. לכן בדרך כלל פתיחה וסביגרה מסודרת אינם יקרים. מה שיקר זה לשמור חיבור פתוח באופן קבוע (מה שגם עלול לגרום לפתיחה של עוד חיבורים מפני שהמקום ב POOL תפוס).

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

    using (SqlConnection conn = new SqlConnection(...))
    {
    using(SqlCommand cmd = new SqlCommand(..., conn))

    { conn.Open(); ... }
    }

    שימוש במתודה חיצונית יכול להיות טוב אבל אני מעדיף את ההוראה של הפתיחה להצמיד לפעולה כדי לוודא את המשפט שהדגשתי מעל.

    בצורה זו המשאבים משתחררים באופן מסודר. יותר מכך! זה לא באמת פותח חיבור בכל הפעלה! כאן נכנס החלק של Connection Pooling. חיבור חדש יפתח רק אם יש שימוש בשרשרת התחברות שונה או שאין חיבור פנוי ב POOL. תזכרי שכל נושא ה Connection Pooling לא קשור ל SQL SERVER אלא מנוהל ברמת האפליקציה. זה חלק מה ADO.NET.

    הפעולה של OPEN לא בהכרח פותחת חיבור חדש (בדרך כלל היא תתלבש על חיבור קיים שנמצא בPOOL)
    הפעולה CLOSE לא מתנתק חיבור אלא רק משחררת אותו ב POOL לטובת שימוש אחר.

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

    * אפשר להגדיר בשרשדרת ההתחברות אם לבטל את השימוש ב POOL

    * כדאי לדעת שברירת המחדל היא ליצור 100 מקומות ב POOL. ניתן לשלוט על ה POOOL באמצעות מאפיינים ומתודות מובנות במחלקה כמו למשל 

    >> "יש מקום מסויים שאני יכולה לעקוב ולראות מה קורה אצלי בפועל?"

    כאמור ה POOL מנוהל ברמת האפליקציה אבל האירועים אצמם נרשמים גם ברת ה SQL, ולכן התשובה היא כן (כמו תמיד הכל אפשר לבצע), את יכולה לנטר את כל הדברים דרך האפליקציה בצורה יותר מעמיקה (בשביל זה מחלקות DEBUG ושיטות נניטור יותר ופחות מורכבות שמאוד מומלץץ להפעיל) או דרך השרת SQL.

    בקישור הבא יש לך דוגמה לנושא: http://stackoverflow.com/questions/6599053/how-to-find-what-is-using-the-connections-in-my-connection-pool

    * אפשר לנטר חיבורים לשרת גם דרך שאילתות בשרת, ולקבל אינפורמציה על החיבורים, אפשר לנטר באמצעות perfmon את הפעולות עצמן, אפשר להחזיק בשרת טבלת לוג ולהכניס אליה נתונים לניטור וניתוח מאוחר יותר או לעבוד עם קובץ לוג... בקיצור כל שיטת ניתור פעולות בשרת ה SQL או בא]פליקציה יככולה לשמש אותנו (בעקרון הדברים החשובים נרשמים גם בשרת ה SQL ובטח ידעועים באפליקציה)


    [Personal Site] [Blog] [Facebook]signature

    • סומן כתשובה על-ידי ssfrank יום ראשון 03 אוגוסט 2014 06:33
    יום שישי 01 אוגוסט 2014 07:17
    מנחה דיון

כל התגובות

  • תבדקי את הקישורים הבאים מכסים את כל השאלות שלך:

    http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

    http://www.w3enterprises.com/articles/using.aspx

    הקישור השני יסביר לך למה את כן מבצעת פתיחה וסגירה של חיבור ומה המשמעות של שימוש ב USING והקישור הראשון יביא לך מידע כללי ויתקן כמה נקודות שהעלית.

    >> דרך אגב הניתור שלך לא נכון מכיוון שהאירוע Audit Login כולל גם אירוע התחברות לשרת וגם אירוע של התחברו ל POOL. את צריכה להוסיף תצוגה של EventSubClass כדי לבצע ניטור נכון.


    [Personal Site] [Blog] [Facebook]signature

    יום חמישי 31 יולי 2014 10:39
    מנחה דיון
  • 1. תודה על הלינקים! הם החכימו אותי.
    2. אכן בדקתי את הEventSubClass והיה כתוב שם: 2 - pooled, אני מבינה שאני אכן לא פותחת כל פעם connection חדש, אבל בכל אופן כמעט כל פעולה שלי פותחת בaduit login ונסגרת בaduit logout, האם זה תקין?
    3. אני חוזרת לקוד שלי (שצרפתי בשאלה), אני אכן משתמשת בusing, אבל אני לא תמיד פותחת connection חדש.
    הפונקציה של getOpenConnection נראת ככה:

    public SqlConnection getOpenConnection()
            {
               
                if (conn == null || conn.State != ConnectionState.Open)
                {
                    string connectionString = "my connection string";
                    SqlConnection thisConnection = new SqlConnection(connectionString);
                    if (thisConnection.State != ConnectionState.Open)
                    {
                        thisConnection.Open();
                    }
                    return thisConnection;
                }
                return conn;
            }

    כאשר האוביקט conn הוא משתנה מחלקה, ותמיד מוחזר, ואני אף פעם לא יוצרת משתנה SqlConnection חדש.

    הפתיחה של הconnection (פונקצית thisConnection.Open()) לא מתבצעת סמוך לפעולת השאילתה, אולי זה בזבוז של הconnection?

    האם ככה ראוי לעשות?

    או שצריך כל פעם ליצור מופע חדש של האוביקט sqlconnection?

    4. שאלה אחרונה, יש מקום מסויים שאני יכולה לעקוב ולראות מה קורה אצלי בפועל? כמה בריכות (pools) פעילות יש אצלי כרגע?

    כמה חיבורים פעילים בכל בריכה וכו... כדי לראות אם אני לא חורגת או שיש משהו מוגזם?

    תודה על כל העזרה!!!!

    שרה.


    • נערך על-ידי ssfrank יום חמישי 31 יולי 2014 13:42
    יום חמישי 31 יולי 2014 13:41
  • בוקר טוב שרה,

    >> "pooled"

    - זה בדיוק מה שציפיתי :-) זה אומר שלא מדובר על חיבור חדש אלא שימוש ב POOL

    >> "בכל אופן כמעט כל פעולה שלי פותחת בaduit login ונסגרת בaduit logout, האם זה תקין?"

    - את צריכה להבין שכל נושא ניהול ה POOL נעשה על ידי האפליציה שלך ולא על שרת ה SQL. למעשה כל השאלה הזו לא קשורה לפורום SQL והיתה צריכה להגיע בפורום C# למשל. תעהרי על הבלוג הבא לעומק (הוא מאוד גם למי שכבר יש לו את הבסיס):

    כמו שכתבתי קודם aduit login וכן aduit logout הם אירועים שיוצגו גם בהתחברות ל POOL וגם בחיבור חדש לשרת. זה פשוט ניטור לא נכון וזו ההתנהגות. אם זה "תקין" או לא זה כבר את צריכה להחליט אבל זו ההתנהגות "הנורמלית" בכל מקרה :-)

    >> לגבי הקוד שלך, הנה כמה נקודות שאולי יעזרו:

    יש חשיבות לסוג היישום כשמדברים על SESSION או CONNECTION וכו, למשל באפליקציה אינטרנטית המעבר לעמוד חדש יוצר בברירת המחדל סגירה של המשאבים של העמוד הקודם (ה IIS מנהל חלק ניכר מהפעולות). אי לנו מידע על סוג האפליקציה שלך...

    - אני אישית מאוד לא אוהב את הגישה של הסתמכות על בלוקים של TRY/CATCH או שימוש בצורות של "אם החיבור לא קיים אז תפתח אותו". בדרך כלל (כמובן לא תמיד), זה מצביע על כך שאת לא יודעת מה קורה באפליקציה וצריכה לבדוק או להסתיר את מה שקורה.

    חיבורים למסד הנתונים דרך ADO.NET אכן בברירת המחדל נכנסים ל POOL. הוראה של פתיחת חיבור חדש לא תמיד יוצרת חיבור חדש אלא מתלבשת על חיבור קיים. לכן בדרך כלל פתיחה וסביגרה מסודרת אינם יקרים. מה שיקר זה לשמור חיבור פתוח באופן קבוע (מה שגם עלול לגרום לפתיחה של עוד חיבורים מפני שהמקום ב POOL תפוס).

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

    using (SqlConnection conn = new SqlConnection(...))
    {
    using(SqlCommand cmd = new SqlCommand(..., conn))

    { conn.Open(); ... }
    }

    שימוש במתודה חיצונית יכול להיות טוב אבל אני מעדיף את ההוראה של הפתיחה להצמיד לפעולה כדי לוודא את המשפט שהדגשתי מעל.

    בצורה זו המשאבים משתחררים באופן מסודר. יותר מכך! זה לא באמת פותח חיבור בכל הפעלה! כאן נכנס החלק של Connection Pooling. חיבור חדש יפתח רק אם יש שימוש בשרשרת התחברות שונה או שאין חיבור פנוי ב POOL. תזכרי שכל נושא ה Connection Pooling לא קשור ל SQL SERVER אלא מנוהל ברמת האפליקציה. זה חלק מה ADO.NET.

    הפעולה של OPEN לא בהכרח פותחת חיבור חדש (בדרך כלל היא תתלבש על חיבור קיים שנמצא בPOOL)
    הפעולה CLOSE לא מתנתק חיבור אלא רק משחררת אותו ב POOL לטובת שימוש אחר.

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

    * אפשר להגדיר בשרשדרת ההתחברות אם לבטל את השימוש ב POOL

    * כדאי לדעת שברירת המחדל היא ליצור 100 מקומות ב POOL. ניתן לשלוט על ה POOOL באמצעות מאפיינים ומתודות מובנות במחלקה כמו למשל 

    >> "יש מקום מסויים שאני יכולה לעקוב ולראות מה קורה אצלי בפועל?"

    כאמור ה POOL מנוהל ברמת האפליקציה אבל האירועים אצמם נרשמים גם ברת ה SQL, ולכן התשובה היא כן (כמו תמיד הכל אפשר לבצע), את יכולה לנטר את כל הדברים דרך האפליקציה בצורה יותר מעמיקה (בשביל זה מחלקות DEBUG ושיטות נניטור יותר ופחות מורכבות שמאוד מומלץץ להפעיל) או דרך השרת SQL.

    בקישור הבא יש לך דוגמה לנושא: http://stackoverflow.com/questions/6599053/how-to-find-what-is-using-the-connections-in-my-connection-pool

    * אפשר לנטר חיבורים לשרת גם דרך שאילתות בשרת, ולקבל אינפורמציה על החיבורים, אפשר לנטר באמצעות perfmon את הפעולות עצמן, אפשר להחזיק בשרת טבלת לוג ולהכניס אליה נתונים לניטור וניתוח מאוחר יותר או לעבוד עם קובץ לוג... בקיצור כל שיטת ניתור פעולות בשרת ה SQL או בא]פליקציה יככולה לשמש אותנו (בעקרון הדברים החשובים נרשמים גם בשרת ה SQL ובטח ידעועים באפליקציה)


    [Personal Site] [Blog] [Facebook]signature

    • סומן כתשובה על-ידי ssfrank יום ראשון 03 אוגוסט 2014 06:33
    יום שישי 01 אוגוסט 2014 07:17
    מנחה דיון
  • תודה על כל המידע!

    עזרת לי מאד!!!

    שרה.

    יום ראשון 03 אוגוסט 2014 06:33
  • בכיף :-) אני שמח לשמוע

    [Personal Site] [Blog] [Facebook]signature

    יום ראשון 03 אוגוסט 2014 10:50
    מנחה דיון