משיב מוביל
בעיית ביצועים בשאילתת UPDATE

שאלה
-
בהמשך ל http://social.msdn.microsoft.com/Forums/he-IL/sqlhe/thread/632f5201-3976-4407-a7bb-1fb4087660b0
יש לי בעיה עם עם השאילתה הבאה :
UPDATE tts set tts.[Content]=t3.IndexId from TargetTable_Staging tts inner join ( select t1.id as PKid,t2.id as IndexId FROM TargetTable t1 inner join Dyn_Content t2 (NOLOCK) ON t1.[Content]=t2.Value COLLATE SQL_Latin1_General_CP1_CI_AS )t3 on tts.id=t3.PKid
היא רצה כמעט 4 דקות! בזמן שכל השאר 10-100 ms.המבנה של הטבלה Dyn_ContentCREATE TABLE [dbo].[Tbl_Content]( [Id] [bigint] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, [Value] [nvarchar](200) NULL, CONSTRAINT [PK_Tbl_Content] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], CONSTRAINT [IX_Content] UNIQUE NONCLUSTERED ( [Value] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
הטבלה TargetTable , היא טבלה זמנית שאני מבצע אליה BULK,ולאחר ה BULK אני בונה לה אינדקסים כולל לעמודת ה CONTENT שהיא מסוג NVARCHAR)200):CREATE NONCLUSTERED INDEX [IX_TargetTable_Content] ON [dbo].[TargetTable] ( [Content] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [FG_INDEX]
מצ"ב ה EXECUTION PLAN-https://www.yousendit.com/download/ZUdzclVBTXZRWUpFQlE9PQרעיונות?
תשובות
-
בוקר טוב
לא עברתי על כל השרשור לעומק אז אני מתנצל מראש אם אני חוזר על משהו שנאמר אבל נראה לי שלא דנתם בדבר הבא וזה יכול לעזור פלאים
תחילה הייתי מבודד לחלוטין את החלק הבא בשאילתה עד לסיום המיטוב שלו:
select t1.id as PKid,t2.id as IndexId
FROM TargetTable t1
inner join Dyn_Content t2 (NOLOCK)
ON t1.[Content]=t2.Value
COLLATE SQL_Latin1_General_CP1_CI_AS
עתה נעבוד רק על חלק זה בלבד: הבעיה כפי הנראה היא בכך שמבוצע כרגע Index Scan במקום Index Seek. 90% מהמשאבים הולכים על סריקת הטבלה.
אם אני מבין נכון הרי ששדה t1.[Content] ושדה t2.Value הם שדות טקסטואליים גדולים ולכן מבוצע סריקה בצורה זו. אחת השיטות לעקוף את הבעיה היא להוסיף שדה מיוחד רק עבור אינדקס שמייצג נכונה את ההטקסט של שדות אלו (בתכנות נעזרים במה שנקרא פונקצית HASH = פונקציה שמגדירה קשר בין מפתח לבין הערכים ואז ניתן לבצע מיון לפי המפתח בצורה מהירה)
אחד הפתרונות לעבודה עם טקסט גדול זה שימוש ב full test search. לכן המלצה ראשונה היא לחשוב/לנסות ביצוע החיבור בין הטבלאות באמצעות השוואה בדרך זו.
הדרך השנייה נקראת Hash indexes ועליה דיברתי מעל. הרעיון הוא ליצור שדה מחושב נוסף בטבלה שיחושב מהשדות הטקסטואליים ועל שדה זה נוכל להקים אינדקס פשוט. את השוואת הנתונים נוכל לבצע על שדה זה כמובן כי הוא מוסס על השדה הטסטואלי שלנו ורק אז נבצע סינון משני בתוצאה הסופית לבדוק שאכן לא קיבלנו בטעות כמה ערכים (פונקציית ההאש שלנו היתה אידאלית אם היתה נותנת יחס של 1:1 בין המקור לשדה המחושב אבל בדרך כלל היחס הוא יחיד לרבים... ז"א יכול להיות מצב תיאורטית אם כי הסיכוי נמוך במקרה של שימוש ב CHECKSUM שכמה טקסטים יקבלו אותו ערך מחושב)
הדוגמה הכי פשוט היא יצירת שדה CHECKSUM על השדה הטקסטואלי שלנו.
ALTER TABLE MyTbl
ADD cs_Txt AS CHECKSUM(Txt);
GO
CREATE INDEX cs_Txt_index ON MyTbl (cs_Txt);
GO
* ניתן כמובן לבחור בפונקצית HASHאחרת על מנת להגדיר את הקשר בין המפתח החדש שונים ובין הטקסט הקיים. עתה כשתבצע שימוש בטבלה תוכל לעשות שימוש בשדה אינדקס זה ולא תיה סריקה של כל הטבלה
- הוצע כתשובה על-ידי EitanBlumin יום שלישי 23 אוגוסט 2011 06:13
- סומן כתשובה על-ידי Ami Levin יום שלישי 23 אוגוסט 2011 11:48
כל התגובות
-
הי,
מתבצע Full clustered index scan על טבלת DYN_Content.
ראשית תןןדא שהעמודה ב- Collation הנכון ותוריד את ה- Cast מה- Join.
שנית תחליף את ה- Unique constraint ב- unique nonclustered index, זה נכון שנבנה index עבור ה- UC אבל יצא לי כבר לגלות שהחלפתי לאינדקס עיניינים הסתדרו.
אני ימשיך לחקור אבל ללא ספק שהבעיה ב- Join בין targetTable ל- Content בשדה Value.
תבודד את ה- Join ואחרי שזה יעיל תוסיף את ה- Update.
אני כמעט בטוח שהאינדקס והורדת Collation תפתור את הבעיה.
יום טוב,
אסף שלם- הוצע כתשובה על-ידי EitanBlumin יום שלישי 23 אוגוסט 2011 06:13
-
-
יש ל יכבר UNIQUE NON CLUSTERED INDEX
ALTER TABLE [dbo].[Dyn_Content] ADD CONSTRAINT [IX_Content] UNIQUE NONCLUSTERED ( [Value] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
זה מספיק? -
הי,
יש לך Unique constraint שמיוצג ע"י nonclustered index.
תוריד את ה- Constraint.
Alter table [dbo].[Dyn_Content] drop constraint [IX_Content]
ותוסיף unique nonclustered index
Create unique nonclustered index idx_Content_Value on table_name (value)
בהצלחה
אסף שלם -
היי,
אשמח אם תוכל/י לעדכן אותנו בסטטוס השאלה שלך.
במידה וקיבלת תשובה מתאימה לשאלתך, יש לסמן את התשובה המתאימה ע"י לחיצה על "סמן כתשובה" ליד סימון ה V הירוק
אם לא קיבלת תשובה, מומלץ לספק פרטים נוספים אודות הבעיה, פרטי לוג, צילומי מסך וכו'
על מנת להעלות תמונה לפורום ניתן להעזר במדריך להעלאת תמונה.
אם תגובתי פתרה את בעייתך - לחץ/י, על "סמן כתשובה" ליד סימן ה V הירוק.
על מנת להעלות תמונה לפורום ניתן להעזר במדריך להעלאת תמונה
מיקרוסופט מציעה שירות זה ללא תשלום, למטרת סיוע למשתמשים והעשרת הידע הקשור בטכנולוגיות ובמוצרים של Microsoft. תוכן זה מתפרסם כפי שהוא והוא אינו מעיד על כל אחריות מצד מיקרוסופט. -
-
-
-
-
הי פלג,
אני לא רואה שיפור ב- Execution Plan.
עדין יש clustered index scan על טבלת Dyn_Content, סריקה של קרוב ל- 11,000,000 רשומות, ואז join עם טבלת Target Tables מה שמוריד את כמות הרשומות ל- 3341.
חייבים לשפר את הנקודה הזו.
אשמח לעזור במידה ואתה מעוניין
אסף שלם -
-
-
-
-
בוקר טוב
לא עברתי על כל השרשור לעומק אז אני מתנצל מראש אם אני חוזר על משהו שנאמר אבל נראה לי שלא דנתם בדבר הבא וזה יכול לעזור פלאים
תחילה הייתי מבודד לחלוטין את החלק הבא בשאילתה עד לסיום המיטוב שלו:
select t1.id as PKid,t2.id as IndexId
FROM TargetTable t1
inner join Dyn_Content t2 (NOLOCK)
ON t1.[Content]=t2.Value
COLLATE SQL_Latin1_General_CP1_CI_AS
עתה נעבוד רק על חלק זה בלבד: הבעיה כפי הנראה היא בכך שמבוצע כרגע Index Scan במקום Index Seek. 90% מהמשאבים הולכים על סריקת הטבלה.
אם אני מבין נכון הרי ששדה t1.[Content] ושדה t2.Value הם שדות טקסטואליים גדולים ולכן מבוצע סריקה בצורה זו. אחת השיטות לעקוף את הבעיה היא להוסיף שדה מיוחד רק עבור אינדקס שמייצג נכונה את ההטקסט של שדות אלו (בתכנות נעזרים במה שנקרא פונקצית HASH = פונקציה שמגדירה קשר בין מפתח לבין הערכים ואז ניתן לבצע מיון לפי המפתח בצורה מהירה)
אחד הפתרונות לעבודה עם טקסט גדול זה שימוש ב full test search. לכן המלצה ראשונה היא לחשוב/לנסות ביצוע החיבור בין הטבלאות באמצעות השוואה בדרך זו.
הדרך השנייה נקראת Hash indexes ועליה דיברתי מעל. הרעיון הוא ליצור שדה מחושב נוסף בטבלה שיחושב מהשדות הטקסטואליים ועל שדה זה נוכל להקים אינדקס פשוט. את השוואת הנתונים נוכל לבצע על שדה זה כמובן כי הוא מוסס על השדה הטסטואלי שלנו ורק אז נבצע סינון משני בתוצאה הסופית לבדוק שאכן לא קיבלנו בטעות כמה ערכים (פונקציית ההאש שלנו היתה אידאלית אם היתה נותנת יחס של 1:1 בין המקור לשדה המחושב אבל בדרך כלל היחס הוא יחיד לרבים... ז"א יכול להיות מצב תיאורטית אם כי הסיכוי נמוך במקרה של שימוש ב CHECKSUM שכמה טקסטים יקבלו אותו ערך מחושב)
הדוגמה הכי פשוט היא יצירת שדה CHECKSUM על השדה הטקסטואלי שלנו.
ALTER TABLE MyTbl
ADD cs_Txt AS CHECKSUM(Txt);
GO
CREATE INDEX cs_Txt_index ON MyTbl (cs_Txt);
GO
* ניתן כמובן לבחור בפונקצית HASHאחרת על מנת להגדיר את הקשר בין המפתח החדש שונים ובין הטקסט הקיים. עתה כשתבצע שימוש בטבלה תוכל לעשות שימוש בשדה אינדקס זה ולא תיה סריקה של כל הטבלה
- הוצע כתשובה על-ידי EitanBlumin יום שלישי 23 אוגוסט 2011 06:13
- סומן כתשובה על-ידי Ami Levin יום שלישי 23 אוגוסט 2011 11:48
-
-