none
בעיית ביצועים בשאילתת UPDATE RRS feed

  • שאלה

  • בהמשך ל 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_Content
    CREATE 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
    רעיונות?

    יום ראשון 14 אוגוסט 2011 11:50

תשובות

  • בוקר טוב

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

    תחילה הייתי מבודד לחלוטין את החלק הבא בשאילתה עד לסיום המיטוב שלו:

    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
    יום שלישי 16 אוגוסט 2011 07:11
    מנחה דיון

כל התגובות

  • הי,

    מתבצע 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
    יום ראשון 14 אוגוסט 2011 13:35
  • תודה על הרעיון

    אני בינתיים עשיתי מסלול עוקף עם לולאה, הוריד לי את הזמן מ 4 דקות ל 8 שניות.

    יום ראשון 14 אוגוסט 2011 13:58
  • יש ל יכבר 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
    

    זה מספיק?

    יום ראשון 14 אוגוסט 2011 14:13
  • הי,

    יש לך 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)

    בהצלחה


    אסף שלם
    יום ראשון 14 אוגוסט 2011 14:26
  • היי,

    אשמח אם תוכל/י לעדכן אותנו בסטטוס השאלה שלך.

     

    במידה וקיבלת תשובה מתאימה לשאלתך, יש לסמן את התשובה המתאימה ע"י לחיצה על "סמן כתשובה" ליד סימון ה V הירוק

    אם לא קיבלת תשובה, מומלץ לספק פרטים נוספים אודות הבעיה, פרטי לוג, צילומי מסך וכו'

    על מנת להעלות תמונה לפורום ניתן להעזר במדריך להעלאת תמונה.


    אם תגובתי פתרה את בעייתך - לחץ/י, על "סמן כתשובה" ליד סימן ה V הירוק.

    על מנת להעלות תמונה לפורום ניתן להעזר במדריך להעלאת תמונה
    מיקרוסופט מציעה שירות זה ללא תשלום, למטרת סיוע למשתמשים והעשרת הידע הקשור בטכנולוגיות ובמוצרים של Microsoft. תוכן זה מתפרסם כפי שהוא והוא אינו מעיד על כל אחריות מצד מיקרוסופט.
    יום שני 15 אוגוסט 2011 05:51
  • הי פלג,

    הסתדר לך ה- Tunning ? במידה ולא יש לי כמה דרכים שאני יכול לייעץ לך ע"מ להבין את ה- Plan ולבדוק למה נבחר Table Scan במקום שימוש ב- Index.

    יום טוב,


    אסף שלם

    יום שני 15 אוגוסט 2011 07:49
  • אני עוד מעט אריץ ויעלה EXECUTION PLAN מעודכן

    אבל עדין יש לי את הבעיה המוזרה של הספירה השגוייה של שורות.

    אפשר לשלוח לך את זה למייל? לתקן ולהעלות פה זה מסובך קצת:(

    יום שני 15 אוגוסט 2011 11:27
  • ביצעתי את השינויים נראה יותר טוב

    זה ה EXECUTIN PLAN החדש :

    https://www.yousendit.com/download/ZUd2aXRDTk1uSlJFQlE9PQ

    יש עוד מה לשפר?

    יום שני 15 אוגוסט 2011 11:42
  • ביצעתי בדיקה נוספת- כשמבצעים את השאילתה על כמות קטנה של שורות -2000, זה יחסית לוקח הרבה זמן.

    השארתי את השינוי שעשינו, אבל ניסיתי על לולאה הוא סיים את זה מהר מאוד.

    יום שני 15 אוגוסט 2011 11:55
  • הי פלג,

    אני לא רואה שיפור ב-  Execution Plan.

    עדין יש clustered index scan על טבלת Dyn_Content, סריקה של קרוב ל- 11,000,000 רשומות, ואז join עם טבלת Target Tables מה שמוריד את כמות הרשומות ל- 3341.

    חייבים לשפר את הנקודה הזו.

    אשמח לעזור במידה ואתה מעוניין

     


    אסף שלם
    יום שני 15 אוגוסט 2011 12:03
  • המייל שלי:

    assaf@toptix.co.il

    אפשר גם בטלפון

    0542208649


    אסף שלם
    יום שני 15 אוגוסט 2011 12:11
  • כן אין שיפור, כמו שאמרתי רק בלולאה זה עובד.
    יום שני 15 אוגוסט 2011 12:21
  • צריך לשפר, לסרוק 11 מיליון רשומות בשביל להוציא 3000, קצת מוגזם.

    יש דרכים לשפר במידה ואתה מעוניין "להתעסק" עם זה


    אסף שלם
    יום שני 15 אוגוסט 2011 12:48
  • אני אשאר עם זה כמו שזה כרגע בלולאה רץ מהיר מספיק.
    יום שני 15 אוגוסט 2011 12:49
  • בוקר טוב

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

    תחילה הייתי מבודד לחלוטין את החלק הבא בשאילתה עד לסיום המיטוב שלו:

    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
    יום שלישי 16 אוגוסט 2011 07:11
    מנחה דיון
  • pituach - נשמע מעניין נבדוק את הסוגיה תודה:)
    יום שלישי 16 אוגוסט 2011 20:30
  • אם אתה רוצה דוגמה פשוטה אשמח לספק

    אם הייתי פחות זהיר הייתי חותם לך שזה ישפר את השאילתה שלך ב 80-85% כי מקור הבעיה אצלך של ה Index Scan שאני וודאי שהוא מיותר ושדרך זו יכולה לעקוף אותו ככל הנראה. ספר היכן זה עומד...


    יום רביעי 17 אוגוסט 2011 13:17
    מנחה דיון