none
השוואה מזעזעת בין JOIN בין טבלאות לJOIN בין שני SubQueries RRS feed

  • שאלה

  • חברים יקרים זו מצוקה קשה אנא,
    יש לי טבלת Positions עם 330 מיליון שורות וטבלת Statuses עם 13 מיליון שורות.
    השאילתא שלהלן מחזירה 575 שורות.
    כאשר אני מריץ את השאילתא בJOIN נורמלי כמו בקוד שלהלן התוצאה חוזרת אחרי 15 דקות(!!)
    SELECT S.ID, S.DTime, Status, Street
      From Statuses S Left Outer Join Positions P
      ON S.ID = P.ID AND S.DTime = P.DTime
      WHERE
         (S.ID = 'YONI' OR S.ID = 'RONI' OR S.ID = 'TONI')
         AND
         S.DTime Between
              '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
         AND
         (P.ID = 'YONI' OR P.ID = 'RONI' OR P.ID = 'TONI')
         AND
         P.DTime Between
              '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
    
    
    לעומת זאת כאשר אני עושה SELECT נפרד לכל אחת מהטבלאות וJOIN בין הSubQueries כלהלן
    SELECT S.ID, S.DTime, Status, Street FROM
    (
    SELECT ID, DTime, Status From Statuses
      WHERE
         (ID = 'YONI' OR ID = 'RONI' OR ID = 'TONI')
         AND DTime Between
                 '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
    ) S
    LEFT OUTER JOIN
    (
    SELECT ID, DTime, Street From Positions
      WHERE
         (ID = 'YONI' OR ID = 'RONI' OR ID = 'TONI')
         AND DTime Between
                 '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
    ) P
    ON S.ID = P.ID AND S.DTime = P.DTime
    
    
    התוצאה חוזרת תוך שתי שניות(!!)
    חשוב לציין שבExcution Plan מוצג הפוך - שהראשון אמור לקחת 0% מהBatch והשני 100%.
    עוד - השדות שעליהם הWhere מאונדקסים
    מודה לכם מקרב לב על עזרתכם.
    יום שלישי 25 אוקטובר 2011 11:12

תשובות

  • תודה על התודה :-)
    אנא סגור את השירשור על ידי סימון תשובה אחת או כמה תשובות. כמו כן מומלץ לסמן תגובות יעילות.
    signature
    • סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
    שבת 29 אוקטובר 2011 15:36
    מנחה דיון
  • הי

    אני הייתי מציע משהו שהוא אמנם לא לפי הספר אבל הוא מועיל...

    להוסיף ל ON חלק מה where ואז החיתוך הוא על הרבה פחות נתונים

    • סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
    יום ראשון 30 אוקטובר 2011 09:35

כל התגובות

  • אנא צרף DDL+DML כדי שנוכל לעזור ולראות את מה שאתה מספר

    עם זה הבעיה דיי ברורה :-) JOIN היא פעולה שיכולה להיות במקרה הקיצוני גם מכפלה קרטזית של נתונים וזה אומר שההבדל בין ביצוע סינון לפני ביצוע ה JOIN יכול לשפר פלאים את השאילתה.
    יום שלישי 25 אוקטובר 2011 11:31
    מנחה דיון
  • תודה מקרב לב, אבל למה אין לSQL את השכל לסנן את שתי הטבלאות לפני הJOIN ואז לבצע את הJOIN כמו בסיפור של הSubQueries.

    מה כוונתך לצרף DDL הלא DML כתבתי ומה עוד נדרש כאן מהו הDDL שצריך כאן.

    תודה

     

    יום שלישי 25 אוקטובר 2011 11:59
  • היי.

    אולי פספסתי משהו, אבל אני לא מבין איפה הבעיה..... ואני מסכים שבמקרה הזה הסינון לפני ה-JOIN מקל על הביצועים.

    לכן - מה רע בו?

    כדי שיראה יותר טוב וקריא, אתה יכול לכתוב אותו דבר עם CTE:

    ; WITH cteStatuses AS
    (
    SELECT ID, DTime, Status From Statuses
      WHERE
         (ID = 'YONI' OR ID = 'RONI' OR ID = 'TONI')
         AND DTime Between
                 '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
    )
    , ctePositions AS
    (
    SELECT ID, DTime, Street From Positions
      WHERE
         (ID = 'YONI' OR ID = 'RONI' OR ID = 'TONI')
         AND DTime Between
                 '2011/10/02 00:00:00' AND '2011/10/24 09:02:00'
    )
    SELECT S.ID, S.DTime, Status, Street FROM
    cteStatuses S
    LEFT OUTER JOIN
    ctePositions P
    ON S.ID = P.ID AND S.DTime = P.DTime
    


    איתי.

     


    itaigitt, http://copypastenet.blogspot.com
    • נערך על-ידי itaigitt יום שלישי 25 אוקטובר 2011 12:02
    יום שלישי 25 אוקטובר 2011 12:01
  • תודה רבה

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

    תודה יוסי מוזס

     

    יום שלישי 25 אוקטובר 2011 12:15
  • אם זה נעשה בתוכנה אתה יכול לשקול (בהתאם למקרה ולקוד הספציפים) להעביר חלק מהלוגיקה (פילטור וכדו') מה-SQL לקוד - יש דברים שמתבצעים בקוד בצורה מהירה יותר, וכך לשפר ביצועים.

    בלא מעט מקרים זהו הפתרון הכי טוב, יעיל ומהיר. לגיטימי לחלק מאמץ בין ה-DB לבין הקוד... :-)


    itaigitt, http://copypastenet.blogspot.com
    יום שלישי 25 אוקטובר 2011 12:29
  • תודה רבה, יוסי
    יום שלישי 25 אוקטובר 2011 12:35
  • הי,

    ה- Subqueries נוצרים לפני ה- Join בהגדרה, כמו כל פעולה מתמטית שמופיע בסוגריים.

    ה- Join בין שני ה- Subqueries היה יעיל יותר מכוון שבכל שאילתא אתה מפלטר רק על שדות מאותה טבלה וכמות הרשומות המוחזרת קטנה.

    לגבי השאלה למה ה- SQL לא מבצע את אותו הדבר, אני שואל אותך איך אתה חושב שהאופטימייזר יעשה אופטימיזציה לשאילתא כזו?.

    דבר נוסף, יש לך אימדקסים על שדות ה- Join ? ע"מ שהשאילתא תרוץ מהר, לפחות כמו ה- Subqueries אתה צריך לגרום ל- Join להיות יעיל ולאחר ה- Join להיות עם מספר מצומצם של רשומות שעליו יופעל ה- Where.

    במידה ואין אינדקס מורכב על ID ו- DATE בשני הטבלאות הייתי מוסיף כזה.

    דבר נוסף אתה עושה את ה- Join כשאר טבלת ה- Inner קטנה במונים מה- Outer הייתי ממליץ לעשות Select from positions left join ststuses.

    ותמיד תזכור, שיש בעיה מסתכלים במראה לא דרך החלון !!! מה אתה מצפה מהאופטימייזר שיכתוב לך את הקוד????

     

    בהצלחה,    


    אסף שלם
    יום שלישי 25 אוקטובר 2011 13:09
  • יוסי ערב טוב

    אני מגיע מתחום הפיתוח והבעיה מוכרת לי

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

    אם אתה לא רוצה להסתבך וזה יכול להיות מספיק מורכב עד כדי כך שגם חברות כמו מייקרוסופט עדיין לא ייצרו את ה ORM המושלם (עוד רגע אגע במילה הזו והמשמעות שלה) אז אתה יכול לעשות שימוש ב ORM מוכן כמו למשל EF שמוביל לתוצאות שהן בדרך כלל מיטביות

    פירוט: ORM = Object-relational mapping היא מערכת ברמת תוכנה שמנהלת את האובייקטים. היום למשל יכול מפתח דוט נט לעבוד עם טכנולוגיה בשם EF = entity framework code first ואז הוא לא צריך בכלל לגשת למסד הנתונים וכל העבודה נעשית ברמת האפליקציה (כולל בנייה של טבלאות חדשות וניהול האוביקטים ולא רק הנתונים עצמם). עבודה עם EF אפשר לבצע עם שפת השאילתות LINQ שבה הרבה יותר קל ליצור שרשרת ברמת תוכנה (לזה היא נועדה בעקרון... לעבודה ברמת התוכנה). ה ORM של ה EF כבר יתרגם לך שאילתות LINQ לשאילתות SQL מאחורי הקלעים

    * בשום אופן אני לא ממליץ להעביר לאליקציה פעולות עיבוד נתונים שאינן נחוצים לאפליקציה כאשר רק תוצאת העיבוד נחוצה לאפליקציה!
    הכוונה למשל שאם אתה מעבד אלף נתונים כדי לקבל 10 תוצאות אז אין הגיון בדרך כלל להעביר אלף נתונים לאליקציה ורק אז לעבד אותם (התעבורה בין השרת IIS לשרת הנתונים יקרה מאוד ומשאירה את הקישור לשרת הנתונים תפוס ופתוח כל הזמן הזה)

    ** אם היה לנו אפיון יותר מדוייק וכמו שביקשתי DDL+DML מלא היה אפשר לעזור יותר ברמת דוגמאות ספציפות ככל הנראה...
    יום שלישי 25 אוקטובר 2011 22:46
    מנחה דיון
  • רונן ואסף תודה רבה לכם, מקרב לב

    יום רביעי 26 אוקטובר 2011 07:55
  • תודה על התודה :-)
    אנא סגור את השירשור על ידי סימון תשובה אחת או כמה תשובות. כמו כן מומלץ לסמן תגובות יעילות.
    signature
    • סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
    שבת 29 אוקטובר 2011 15:36
    מנחה דיון
  • הי

    אני הייתי מציע משהו שהוא אמנם לא לפי הספר אבל הוא מועיל...

    להוסיף ל ON חלק מה where ואז החיתוך הוא על הרבה פחות נתונים

    • סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
    יום ראשון 30 אוקטובר 2011 09:35