none
sql list parameter RRS feed

  • שאלה

  • שלום לכולם!!

    יש לי מערך של strings שכל איבר בו אני צריכה לשמור בDB.

    יש לי stored procedure שמקבל nvarchar ושומר אותו כשורה בטבלה.

    בגלל שיש לי מערך גדול מאד זה יוצר עומס גדול מאד בסרבר של הDB.

    חשבתי אולי שיהיה יותר חכם שהSQL יקבל את המערך ויעשה לבד את העבודה.

    זה מקובל? יש אפשרות? רעיון אחר?

    תודה!!!!

    שרה.

    יום שני 15 ספטמבר 2014 08:10

תשובות

כל התגובות

  • שרה שלום רב,

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

    1.  Table Valued Parameters

    2. XML parameter

    3. List parsing

    לכל שיטה יש יתרונות וחסרונות.

    למידע נוסף http://dba.stackexchange.com/questions/629/passing-array-parameters-to-a-stored-procedure

    בהצלחה !!


    Best Regards,

    Itai Binyamin, MVP

    www.ItaiBinyamin.Blogspot.com


    • נערך על-ידי Itai Binyamin יום שני 15 ספטמבר 2014 09:18 .
    • הוצע כתשובה על-ידי pituachMVP, Moderator יום שני 15 ספטמבר 2014 17:52
    • סומן כתשובה על-ידי ssfrank יום שלישי 16 ספטמבר 2014 08:48
    יום שני 15 ספטמבר 2014 09:16
  • תודה רבה!!

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

    תודה!!!!!

    שרה.

    יום שני 15 ספטמבר 2014 09:21
  • צהריים טובים שרה,

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

    עם זה, אם אני מבין את המקרה שלך אז אינן מתאימות לך.

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

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

    >> השיטה השנייה צורכת הרבה משאבים בפירסור של טקס בצד השרת, היא יוצרת תעבורה גדולה (יש סיבה שרוב המפחים עבור לעבוד עם JSON במקום XML), ואינה מומלצת כמעט בשום מקרה, בפיתוח.

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

    אני מאוד ממליץ לבדוק על כיוון שונה לחלוטין של שימוש ב BULK INSERT.

    ישנה מחלקה מובנית בדוט-נט שנועדה בדיוק לצורך זה של העברת מידע רב ישירות לטבלה. המחלקה נקראת SqlBulkCopy. השימוש בה מאוד פשוט ובפקודה אחת מבצעים העברה של כל הטבלה שלך, מצד האפליקציה אל השרת, בשיטת BULK INSERT. שיטה זו היא גם הרבה יותר יעילה בחינת השרת SQL (בעיקר אם עובדים במצב SIMPLE או מצב BULK במסד הנתונים).

    הקישור הבא נותן הדרכה מלאה כולל דוגמה:
    http://msdn.microsoft.com/en-us/library/ex21zs8x(v=vs.110).aspx

    אני מקווה שזה עונה על הצרכים שלך :-)

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


    [Personal Site] [Blog] [Facebook]signature

    יום שני 15 ספטמבר 2014 14:41
    מנחה דיון
  • תודה על כל התגובות!!!!!

    הסתכלתי קצת על BULK INSERT וזה נראה שזה משמש ליצירת טבלה (או כמה) והכנסה של נתונים פעם אחת.
    אני צריכה הרבה מאד פעמים (UPDATE), ככה שנראה לי שבישבילי זה לא מתאים הפעם.

    יצרתי את השאילתה עם Table Valued Parameters וזה אכן שיפר ביצועים, אבל לא מספיק.

    יש לי עדיין כמה שאלות, לא כולם קשורות לנושא השאלה:

    1. List parsing - לא הבנתי בדיוק את הכוונה, ולא מצאתי חומר ברשת. יש לזה עוד שם?
    2. איך שאני מבינה הפקק נוצר ברגע שאני שולחת כמות נתונים גדולה, כן? 
    אם ככה, זה נראה, שאולי עדיף לשלוח את הנתונים כstring ארוך ופשוט לעשות stpit (PATINDEX) ברגע שאני מגיעה לDB וככה יש לי כמין מערך. זה לא ישפר את התעבורה?

    3. השאילתה שלי משתמשת ב EXECUTE sp_executesql בגלל שיש לי הרבה טבלאות עם סכמות שונות וכל פעם אני קוראת לסכמה שונה, לכן השאלתה צריכה להיות דינמית.

    השאלה שלי, האם הפעולה של EXECUTE sp_executesql כבידה? אולי כדאי לי ליצור שאילתה בפני עצמה לכל סכמה?

    שוב תודה על הכל!!!!!
    שרה.
    יום שלישי 16 ספטמבר 2014 05:58
  • הסתכלתי קצת על BULK INSERT וזה נראה שזה משמש ליצירת טבלה (או כמה) והכנסה של נתונים פעם אחת.
    אני צריכה הרבה מאד פעמים (UPDATE), ככה שנראה לי שבישבילי זה לא מתאים הפעם.

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

    הייתרון בעבודה עם BULK מתבטא הן בצד הלקוח (האפליקציה שלך), הן בצד התעבורה (מכיוון שניתן להעביר את המידע בגדלים התואמים את הגדרות התקשורת בין המחשבים), והן בצד השרת SQL בו ניתן לראות שיפור ניכר במשאבים בעיקר עם מסד הנתונים מוגדר ב Recovery Models של simple או Bulk. מצד שני אין משמעות לשימוש ב BULK עבור נתון בודד.

    תיאורטית בכל מצב ש BULK מתאים לאפיון האפליקציה חובה לעבוד בצורה כזו! אם רוצים לעבוד עם הכנסה של מספר נתונים (נניח מעל 5 ובטח אם מדובר במאות אלפי נתונים). זה כלל אצבע חשוב מאוד.

    יצרתי את השאילתה עם Table Valued Parameters וזה אכן שיפר ביצועים, אבל לא מספיק.

    TVP לא משפר ביצועים בצד הלקוח בכלל אלא רק בצד השרת. ז"א כמובן שזה עדיף גם בצד הלקוח אם קודם ביצעת לולאות ושלחת כל שורה בנפרד, אבל במקרה זה הדבר נכון בכל שיטה בה את מעבירה את כל הנתונים ביחד. הייתרון של TVP זה שהשרת SQL לא צריך לפרסר (לנתח ולפרק) את הטקסט לרכיבים אלא שהוא כבר מגיע במבנה טבלאי (בדיוק כמו BULK אבל ללא כל הייתרונות של BULK בהכנסת נתונים רבים, אבל עם היתרון בהעברה ל SP בשרת ולא רק לטבלה ישירות). כמו שכתבתי זו הדרך המועדפת עלי, במקרה שאני לא צריך להכניס נתונים לטבלה אלא להעביר אותם ל SP לניתוח בצד השרת. למשל אם אני רוצה בצד השרת בלי שהמפתח של האפליקציה ידע, לבצע פעולה נוספת על הנתונים. ברוב המקרים כאשר יש שליטה על האפליקציה זו אינה דרך מתאימה מפני שהדרך הנכונה היא להכין מראש את הנתונים מראש בצד האפליקציה כך שיכנסו לטבלה בצורה  ישירה.

    זה פתרון של DBA נותן את הדר המיטבית הרבה פעמים למשל כאשר הוא צריך לבצע בדיקות על הנתונים, לעבד את הנתונים המגיעים ולהפיק מהם נתונים שונים שצריכים להיכנס לטבלה (למשל מעבירים נתונים X ו Y ולטבלה מכניסים X+Y). כאמור במקרה שלמפתחם ו טעות בדרך כלל וצריך לבצע את העיבד בצד האפליקציה.

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

    >יש לי עדיין כמה שאלות, לא כולם קשורות לנושא השאלה:

    ...

    1. List parsing - לא הבנתי בדיוק את הכוונה, ולא מצאתי חומר ברשת. יש לזה עוד שם?

    הכוונה למשל להעביר ל SP או פונקציה טקסט בודד הכולל כמה נתונים מופרדים בפסיק. זה משפר את העבודה על העברה של נתון בודד בנפרד (את אמורה לראות אותו דיפוטר בדיוק כמו ב TVP בצד האפליקציה), אבל ה אומר שבצד המקבל את האינפורמציה תצתרכי לבצע פעולה של SPLIT כדי להפריד את הנתונים.

    * במקרה של מספר בודדים קטן, ואם עובדים נכו בצד השרת SQL עם CLR אז הפועלה של ה SPLIT יחסית מהירה. עיין זה הרבה פחות יעיל מ TVP מכיוון שיש לבצע את פעולת הניתוח של הטקסט ובדרך כלל באפליקציות אינרנטיות בכלל לא תרגישי הבדל בגלל שצוואר הבקבוק הוא בתעבורה. כאן בנקודה של התעבורה, יהיה מיטוב גדול בכל השיטות בהן מעבירים את הנתונים ביחד (BULK נותן ייתרון גם כאן, אחרי כן יגיע ביחד ללא הבדל TVP או List parsing ואחרו השיטה של להעביר נתון בודד בכל פעם). כמובן גם כאן מדובר על כללי זהב ויש יוצאים מהכלל (יוצאים מהכלל שארכיטקט תוכנה סביר אמור להכיר ולאפיין כשהוא מכיר את המערכת).

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

    אנחנו לא יכולים לדעת מה קורה אצלך. ה חלק מהתפקיד שלך לאתר את צוואר הבקבוק ולבחור את הדרך המאימה. ישנם מערכות בהם דןןקא העבורה של נתון בודד בכל פעם תהיה עדיפה (מעט מאוד מערכות ומצבים ובדרך הכללי אצבע או כללי ההב שולטים). בדרך כלל צריך לבדוק 3 חלקים באפליקציה מרוחקת: (1) מיטוב באפליקציה עצמה (2) תעבורה (3) מה קורה בצד השרת. בנוסף יש לקחת בחשבון את ההתקשרות בין השרת ללקוח (הלקוח הוא האפליקציה כאן)

    אם ככה, זה נראה, שאולי עדיף לשלוח את הנתונים כstring ארוך ופשוט לעשות stpit (PATINDEX) ברגע שאני מגיעה לDB וככה יש לי כמין מערך. זה לא ישפר את התעבורה?

    בבשום אופן לא!!!

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

    ראי את המאמר הבא!
    http://sqlperformance.com/2012/07/t-sql-queries/split-strings
    ההבדלים יכולים להיות של פי מליארד ויותר! הבדלים של שעה לעומת שנייה ויותר (תלוי כמובן בנתונים עצמם שמעבירים)

    בכל מקרה בשיטת BULK וגם בשיטת TVP אנחנו מעבירים את הנתונים בפעם אחת מבחינת האפליקציה, ולכן אין יתרון לשירשור שלהם (אופן ההעברה יכול להיות מעט שונה ואני מעגל קצ פינות לגבי הבדלים, כאן נכנס BULK למשל עם הייתרונות שלו בניהול אופן העברה, למשל בהגדרות שונות).

    >> יש שיטה נוספת שלא דיברנו עליה ויש לה יתרונות רבים. העברה של הדטא כ JSON. כאן נכנס פונקציית ניתוח בצד השרת (שוב פונקציית CLR). זה דומה לשרשור הנתונים אבל מאפשר שליטה טובה יותר על הנתונים ופחות שגיאות (למשל שימוש בפסיק בתוכן של נתון במן שפסיק מהווה הפרדה ועוד, JSON ולא XML בשום מקרה!).

    >3. השאילתה שלי משתמשת ב EXECUTE sp_executesql בגלל שיש לי הרבה טבלאות עם סכמות שונות וכל פעם אני קוראת לסכמה שונה, לכן השאלתה צריכה להיות דינמית.

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

    אני לא יכול להשיב בלי להכיא את המערכת לאפיין אותה, מה מתאים במקרה שלך.

    השאלה שלי, האם הפעולה של EXECUTE sp_executesql כבידה? אולי כדאי לי ליצור שאילתה בפני עצמה לכל סכמה?
    צריך לבדוק ספציפית כל מקרה לגופו, אם כי הרבה פעמים הפתרון הוא בצד הפיתוח (האפליקציה) ולא בשימוש בשאילתה דינאמית. בעבודה עם SP יש משהו מעט שונה לגבי כלל זה מכיוון שכאן בכל מקרה הניתוח נעשה בצד השרת. בעבודה עם שאילתות דינמיות נכנסות שאלות הקשורות גם לניתוח שהשרת מבצע על השאילתות עצמן ומיטוב השאילתות (תוכנית ההרצה שלהן). בנקודה זו, של מטוב השאילתה עצמה בצד השרת, יכולה להיות לשאילתה דינאמית ייתרון גדול, בעבודה נכונה.

    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 16 ספטמבר 2014 07:16
    מנחה דיון
  •  

    וואו!! תודה!!!!!
    משהו קטן לסיום, כי כן השתכנעתי מהBULK INSERT.

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

    זה הdata type שיצרתי:

    CREATE TYPE [dbo].[Contents] AS TABLE(
    	[sentence] [nvarchar](1000) NULL,
    	[count] [int] NULL
    )

    ALTER PROCEDURE [CopyGlobal].[Crawler_contentPagesSents_AddForPage_list]
    	@userId int,
    	@websiteId int,
    	@pageId int,
    	@sentences [dbo].[Contents] Readonly
    	
    AS
    BEGIN
    DECLARE @ID int,@resId int,@Query NVARCHAR(1000),@sentence nvarchar(1000),@count int
    
    DECLARE sen CURSOR FOR
    	SELECT sentence,count FROM @sentences 
    	
    	OPEN sen  
    	FETCH NEXT FROM sen INTO @sentence,@count
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    	SET @query='SELECT @ID=ID FROM  s' +CAST(@userId as varchar(10)) +'.Crawler_contentPagesSents
    WHERE websiteId=@websiteId AND sentence=@sentence'
    	EXECUTE sp_executesql @query, N'@ID int OUTPUT,@websiteId int,@sentence nvarchar(1000)',
        @ID OUTPUT,@websiteId = @websiteId,@sentence = @sentence
    
       
       IF(@ID is null)
       BEGIN
       SET @query='INSERT INTO s' +CAST(@userId as varchar(10)) +'.Crawler_contentPagesSents (websiteId,sentence,count) VALUES 
    	(@websiteId,@sentence,@count)'
    	EXECUTE sp_executesql @query, N'@websiteId int ,@sentence NVARCHAR(1000),@count int',
    	@websiteId = @websiteId,@sentence=@sentence,@count =@count
       
    	SELECT @ID = IDENT_CURRENT( 's' +CAST(@userId as varchar(10)) +'.Crawler_contentPagesSents' )
       END 
       
       SET @query='SELECT @resId=sentId FROM s' +CAST(@userId as varchar(10)) +'.Crawler_pagesToSents
       WHERE sentId=@ID AND pageId=@pageId'
    	EXECUTE sp_executesql @query, N'@resId int OUTPUT,@ID int,@pageId int',
        @resId OUTPUT,@ID = @ID,@pageId = @pageId
       
       
       IF(@resId is null)
       BEGIN
       
       SET @query='INSERT INTO s' +CAST(@userId as varchar(10)) +'.Crawler_pagesToSents (sentId,pageId)
    		VALUES (@ID,@pageId)'
    	EXECUTE sp_executesql @query, N'@ID int,@pageId int',
    	@ID = @ID,@pageId=@pageId
       
       
       END
    	FETCH NEXT FROM sen INTO @sentence,@count
    	END
    
    END
    

    הפרוצדורה מקבלת רשימת פרמטרים ולכל רכיב ברשימה בודקת אם הוא קיים אם לא יוצרת אותו ומקבלת ID, אם כן מקבלת ID שלו.

    ואח"כ עוברת על עוד טבלה משנית ויוצרת (אם צריך) רשומה גם שם.

    השאלה היא אם BULK INSERT אפשרי פה בכלל, כי זה לא סתם השמה פשוטה.

    וגם אם אין לי אפשרות לדלג על השאלה אם השורה קיימת בDB (יש לי constaraint לשדות שעליהם אני שואלת)

    אני כבר מתביישת להגיד תודה... :(

    שרה.

    יום שלישי 16 ספטמבר 2014 07:44
  • בוקר טוב,

    1. הרעיון ב- list parsing הינו לשלוח לפרוצדורה (לדוגמא) סטרינג עם ערכים (מופרדים ב- delimiter) והפרוצדורה "מפענחת" את הערכים .

    לדוגמא:
    http://stackoverflow.com/questions/5493510/turning-a-comma-separated-string-into-individual-rows


    2. בנוגע לעניין הביצועים בשימוש ב- executesql  אז כמובן יש יתרונות וחסרונות , חשוב שתדעי שישנם מקרים בהם השימוש בו גורם לבעיות ביצועים עקב parameter sniffing
    לפרטים נוספים:

    http://pratchev.blogspot.be/2007/08/parameter-sniffing.html


    Best Regards,

    Itai Binyamin, MVP

    www.ItaiBinyamin.Blogspot.com


    • נערך על-ידי Itai Binyamin יום שלישי 16 ספטמבר 2014 08:00 .
    • הוצע כתשובה על-ידי Itai Binyamin יום שלישי 16 ספטמבר 2014 17:02
    • הצעה כתשובה בוטלה על-ידי Itai Binyamin יום שלישי 16 ספטמבר 2014 17:02
    יום שלישי 16 ספטמבר 2014 08:00
  • לא עברתי על הקוד, מפני שאין לי זמןו כרגע, אני רק בהפסקת קפה קצרה

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


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 16 ספטמבר 2014 08:46
    מנחה דיון
  • טוב, תודה בכל אופן!

    עזרת לי המון!!!

    יום שלישי 16 ספטמבר 2014 08:48
  • בכיף :-) 

    אני שמח לשמוע


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 16 ספטמבר 2014 20:15
    מנחה דיון
  • הי שרה,

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

    הנה איך שזה צריך להיראות:

    ALTER PROCEDURE
    	CopyGlobal.Crawler_contentPagesSents_AddForPage_list
    (
    	@userId		AS INT ,
    	@websiteId	AS INT ,
    	@pageId		AS INT ,
    	@sentences	AS dbo.Contents	READONLY
    )
    AS
    
    DECLARE
    	@contentPagesSents_TableName	AS SYSNAME			= N's' + CAST(@userId AS SYSNAME) + N'.Crawler_contentPagesSents' ,
    	@pagesToSents_TableName			AS SYSNAME			= N's' + CAST(@userId AS SYSNAME) + N'.Crawler_pagesToSents' ,
    	@Query							AS NVARCHAR(MAX) ,
    	@ParametersDefinition			AS NVARCHAR(MAX);
    
    SET @Query =
    	N'
    		INSERT INTO
    			' + @contentPagesSents_TableName + N'
    		(
    			websiteId ,
    			sentence ,
    			count
    		)
    		SELECT
    			websiteId	= @p_websiteId ,
    			sentence	= Source.sentence ,
    			count		= Source.count
    		FROM
    			@p_sentences AS Source
    		WHERE
    			NOT EXISTS
    				(
    					SELECT
    						NULL
    					FROM
    						' + @contentPagesSents_TableName + N' AS Target
    					WHERE
    						Target.websiteId = @p_websiteId
    					AND
    						Target.sentence = Source.sentence
    				);
    	';
    
    SET @ParametersDefinition = N'@p_websiteId AS INT , @p_sentences AS dbo.Contents READONLY';
    
    EXECUTE sys.sp_executesql
    	@statement		= @Query ,
    	@params			= @ParametersDefinition ,
    	@p_websiteId	= @websiteId ,
    	@p_sentences	= @sentences;
    
    SET @Query =
    	N'
    		INSERT INTO
    			' + @pagesToSents_TableName + N'
    		(
    			sentId ,
    			pageId
    		)
    		SELECT
    			sentId	= Reference.ID ,
    			pageId	= @p_pageId
    		FROM
    			@p_sentences AS Source
    		INNER JOIN
    			' + @contentPagesSents_TableName + N' AS Reference
    		ON
    			Source.sentence = Reference.sentence
    		WHERE
    			Reference.websiteId = @p_websiteId;
    	';
    
    SET @ParametersDefinition = N'@p_pageId AS INT , @p_websiteId AS INT , @p_sentences AS dbo.Contents READONLY';
    
    EXECUTE sys.sp_executesql
    	@statement		= @Query ,
    	@params			= @ParametersDefinition ,
    	@p_pageId		= @pageId ,
    	@p_websiteId	= @websiteId ,
    	@p_sentences	= @sentences;
    GO
    

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

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

    בהצלחה!

    -----------------------------
    גיא גלנצר
    יועץ ומדריך SQL Server
    Madeira - SQL Server Services
    http://www.madeirasql.com

    יום רביעי 17 ספטמבר 2014 04:09
    מנחה דיון
  • כמה שאתה צודק.... :(

    למדתי הרבה מזה (לא רק ספציפית לשאילה הזו..)

    תודה רבה!!! עזרת לי מאד מאד!!!!!

    שרה.


    יום רביעי 17 ספטמבר 2014 10:00