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

שאלה
-
חברים יקרים זו מצוקה קשה אנא,יש לי טבלת 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 מאונדקסיםמודה לכם מקרב לב על עזרתכם.
תשובות
-
- סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
-
הי
אני הייתי מציע משהו שהוא אמנם לא לפי הספר אבל הוא מועיל...
להוסיף ל ON חלק מה where ואז החיתוך הוא על הרבה פחות נתונים
- סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
כל התגובות
-
אנא צרף DDL+DML כדי שנוכל לעזור ולראות את מה שאתה מספר
עם זה הבעיה דיי ברורה :-) JOIN היא פעולה שיכולה להיות במקרה הקיצוני גם מכפלה קרטזית של נתונים וזה אומר שההבדל בין ביצוע סינון לפני ביצוע ה JOIN יכול לשפר פלאים את השאילתה.- נערך על-ידי pituachMVP, Moderator יום שלישי 25 אוקטובר 2011 11:32
-
-
היי.
אולי פספסתי משהו, אבל אני לא מבין איפה הבעיה..... ואני מסכים שבמקרה הזה הסינון לפני ה-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
-
-
אם זה נעשה בתוכנה אתה יכול לשקול (בהתאם למקרה ולקוד הספציפים) להעביר חלק מהלוגיקה (פילטור וכדו') מה-SQL לקוד - יש דברים שמתבצעים בקוד בצורה מהירה יותר, וכך לשפר ביצועים.
בלא מעט מקרים זהו הפתרון הכי טוב, יעיל ומהיר. לגיטימי לחלק מאמץ בין ה-DB לבין הקוד... :-)
itaigitt, http://copypastenet.blogspot.com -
-
הי,
ה- Subqueries נוצרים לפני ה- Join בהגדרה, כמו כל פעולה מתמטית שמופיע בסוגריים.
ה- Join בין שני ה- Subqueries היה יעיל יותר מכוון שבכל שאילתא אתה מפלטר רק על שדות מאותה טבלה וכמות הרשומות המוחזרת קטנה.
לגבי השאלה למה ה- SQL לא מבצע את אותו הדבר, אני שואל אותך איך אתה חושב שהאופטימייזר יעשה אופטימיזציה לשאילתא כזו?.
דבר נוסף, יש לך אימדקסים על שדות ה- Join ? ע"מ שהשאילתא תרוץ מהר, לפחות כמו ה- Subqueries אתה צריך לגרום ל- Join להיות יעיל ולאחר ה- Join להיות עם מספר מצומצם של רשומות שעליו יופעל ה- Where.
במידה ואין אינדקס מורכב על ID ו- DATE בשני הטבלאות הייתי מוסיף כזה.
דבר נוסף אתה עושה את ה- Join כשאר טבלת ה- Inner קטנה במונים מה- Outer הייתי ממליץ לעשות Select from positions left join ststuses.
ותמיד תזכור, שיש בעיה מסתכלים במראה לא דרך החלון !!! מה אתה מצפה מהאופטימייזר שיכתוב לך את הקוד????
בהצלחה,
אסף שלם- הוצע כתשובה על-ידי pituachMVP, Moderator יום רביעי 02 נובמבר 2011 16:19
-
יוסי ערב טוב
אני מגיע מתחום הפיתוח והבעיה מוכרת לי
אבל גם הפתרון מוכר והוא בדרך כלל באפיון של האפליקציה החיצונית לביצוע פילטור טוב יותר של השאילתה.
אם אתה לא רוצה להסתבך וזה יכול להיות מספיק מורכב עד כדי כך שגם חברות כמו מייקרוסופט עדיין לא ייצרו את ה ORM המושלם (עוד רגע אגע במילה הזו והמשמעות שלה) אז אתה יכול לעשות שימוש ב ORM מוכן כמו למשל EF שמוביל לתוצאות שהן בדרך כלל מיטביות
פירוט: ORM = Object-relational mapping היא מערכת ברמת תוכנה שמנהלת את האובייקטים. היום למשל יכול מפתח דוט נט לעבוד עם טכנולוגיה בשם EF = entity framework code first ואז הוא לא צריך בכלל לגשת למסד הנתונים וכל העבודה נעשית ברמת האפליקציה (כולל בנייה של טבלאות חדשות וניהול האוביקטים ולא רק הנתונים עצמם). עבודה עם EF אפשר לבצע עם שפת השאילתות LINQ שבה הרבה יותר קל ליצור שרשרת ברמת תוכנה (לזה היא נועדה בעקרון... לעבודה ברמת התוכנה). ה ORM של ה EF כבר יתרגם לך שאילתות LINQ לשאילתות SQL מאחורי הקלעים
* בשום אופן אני לא ממליץ להעביר לאליקציה פעולות עיבוד נתונים שאינן נחוצים לאפליקציה כאשר רק תוצאת העיבוד נחוצה לאפליקציה!
** אם היה לנו אפיון יותר מדוייק וכמו שביקשתי DDL+DML מלא היה אפשר לעזור יותר ברמת דוגמאות ספציפות ככל הנראה...
הכוונה למשל שאם אתה מעבד אלף נתונים כדי לקבל 10 תוצאות אז אין הגיון בדרך כלל להעביר אלף נתונים לאליקציה ורק אז לעבד אותם (התעבורה בין השרת IIS לשרת הנתונים יקרה מאוד ומשאירה את הקישור לשרת הנתונים תפוס ופתוח כל הזמן הזה)- נערך על-ידי pituachMVP, Moderator יום שלישי 25 אוקטובר 2011 23:04
- הוצע כתשובה על-ידי pituachMVP, Moderator יום רביעי 02 נובמבר 2011 16:19
-
-
- סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33
-
הי
אני הייתי מציע משהו שהוא אמנם לא לפי הספר אבל הוא מועיל...
להוסיף ל ON חלק מה where ואז החיתוך הוא על הרבה פחות נתונים
- סומן כתשובה על-ידי Yossi Moses ISR יום חמישי 17 נובמבר 2011 14:33