Monday 18 December 2017

T - sql بسيط الحركة من المتوسط


دعونا نقول لديك جدول مع حوالي 5 ملايين السجلات والعمود نفارتشار (ماكس) يسكن مع بيانات النص كبيرة. تريد تعيين هذا العمود إلى نول إذا سوموثيركولومن 1 في أسرع طريقة ممكنة. القوة الغاشمة أوبديت لا يعمل بشكل جيد جدا هنا لأنه سيخلق صفقة كبيرة ضمنية واتخاذ إلى الأبد. القيام التحديثات في دفعات صغيرة من سجلات 50K في وقت يعمل ولكن لا يزال يأخذ 47 ساعة لإكمال على بيفي 32 core64GB الخادم. هل هناك أي طريقة للقيام بهذا التحديث بشكل أسرع هل هناك أي خيارات الجدول تلميحات الاستعلام السحري أن التضحيات شيء آخر (مثل التزامن) في مقابل السرعة ملاحظة: إنشاء جدول تيمب أو عمود مؤقت ليس خيارا لأن هذا نفارتشار (ماكس) العمود يتضمن الكثير من البيانات وهكذا يستهلك الكثير من الفضاء بس: نعم، فهرسة سوميثوراكولومن بالفعل. وأنا أتفق، ونحن بانتظام القيام بتحديثات مثل هذا على الجداول مع 50 مليون أو حتى 500 مليون السجلات ويحدث في ثوان. وأود أن أعتقد أن خطة الاستعلام المحدد ليست الأمثل جدا وأخذ الكثير من الوقت. لقد حدث هذا لي عندما يكون هناك قيود مفتاح أجنبي على جدول آخر على عمود غير مفهرسة. بعد النظر في خطة الاستعلام أدركنا أنه كان لمسح الجدول الآخر لكل حذف الذي كان الجاني. كان هذا 23 مليون الصفوف، وفهرسة الجدول الآخر جلب حذف أسفل إلى أقل من 5 ثوان. نداش كوبسف يونيو 7 10 في 10:46 من كل شيء أستطيع أن أرى أنه لا يبدو أن المشاكل الخاصة بك ترتبط الفهارس. يبدو أن المفتاح في حقيقة أن الحقل نفارتشار (ماكس) يحتوي على الكثير من البيانات. فكر في ما يجب القيام به سكل من أجل تنفيذ هذا التحديث. بما أن العمود الذي تقوم بتحديثه يحتمل أن يكون أكثر من 8000 حرف يتم تخزينه خارج الصفحة، مما يعني جهدا إضافيا في قراءة هذا العمود عندما لا يكون نول. عند تشغيل دفعة من 50000 التحديثات سكل لديه لوضع هذا في معاملة ضمنية من أجل جعل من الممكن التراجع في حالة وجود أي مشاكل. من أجل التراجع لديها لتخزين القيمة الأصلية للعمود في سجل المعاملات. على افتراض (للبساطة) أن كل عمود يحتوي على متوسط ​​10000 بايت من البيانات، وهذا يعني أن 50،000 صف تحتوي على حوالي 500 ميغابايت من البيانات، التي يجب أن يتم تخزينها مؤقتا (في وضع الاسترداد البسيط) أو بشكل دائم (في وضع الاسترداد الكامل). لا توجد طريقة لتعطيل السجلات لأنها سوف تضر بسلامة قاعدة البيانات. ركضت اختبارا سريعا على كلبي ببطء سطح المكتب، وتشغيل دفعات من 10،000 حتى يصبح بطيئا بشكل محتمل، ولكن جلب حجم وصولا الى 1000 الصفوف، مما يعني وجود حجم سجل مؤقت من حوالي 10MB، عملت لطيفا. أنا تحميل جدول مع 350،000 الصفوف ووضع علامة 50،000 منهم للتحديث. هذا الانتهاء في حوالي 4 دقائق، وبما أنه جداول خطيا يجب أن تكون قادرا على تحديث الخاص بك 5 ملايين الصفوف بأكملها على بلدي الكلب سطح المكتب بطيئة في حوالي 6 ساعات على بلدي 1 معالج 2GB سطح المكتب، لذلك أتوقع شيئا أفضل بكثير على الخادم الخاص بك بيفي المدعومة بواسطة سان أو شيء. قد تحتاج إلى تشغيل عبارة التحديث كخيار، وتحديد المفتاح الأساسي فقط وعمود نفارتشار كبير، وضمان تشغيل هذا بأسرع ما تتوقع. بالطبع عنق الزجاجة قد تكون المستخدمين الآخرين تأمين الأشياء أو الخلاف على التخزين أو الذاكرة على الخادم، ولكن بما أنك لم تذكر المستخدمين الآخرين وسوف نفترض لديك دب في وضع المستخدم واحد لهذا الغرض. وكتحسين يجب التأكد من أن سجلات المعاملات على مجموعة قرص قرص فعلي مختلف عن البيانات لتقليل أوقات البحث. هذا ساعدني حقا. ذهبت من 2 ساعة إلى 20 دقيقة مع هذا. في تجربتي، العمل في مسكل 2005، تتحرك يوميا (تلقائيا) 4 مليون 46-بايت السجلات (لا نفارتشار (ماكس) على الرغم من جدول واحد في قاعدة بيانات إلى جدول آخر في قاعدة بيانات مختلفة يستغرق حوالي 20 دقيقة في كوادكور 8GB ، 2Ghz الخادم وأنه لا يضر أداء التطبيق. بالانتقال أعني إنزيرت إنتو سيليكت ثم ديليت. استخدام وحدة المعالجة المركزية أبدا يذهب أكثر من 30، حتى عندما يتم حذف الجدول لديها سجلات 28M ويجعل باستمرار حول 4K إدراج في الدقيقة الواحدة ولكن لا توجد تحديثات. حسنا، هذه هي حالتي، قد تختلف اعتمادا على تحميل الخادم الخاص بك. يحدد أن البيانات (تحديثاتك) يمكنها قراءة الصفوف التي تم تعديلها بواسطة معاملات أخرى ولكن لم يتم الالتزام بها بعد. في حالتي، السجلات هي قراءة. أنا لا أعرف ما يعني رغ-تسكل ولكن هنا سوف تجد معلومات حول مستويات العزلة المعاملات في مسكل. كن حذرا دائما وتأكد من فهمك لآثار قراءة المعاملات غير الملغاة. نعم لن تضطر العملية الخاصة بك إلى انتظار المعاملات المفتوحة لارتكابها قبل حذف العناصر، ولكن بالطبع إذا لم يتم تنفيذ المعاملة بعد كل هذا يعني أنك حذف الصف بشكل غير صحيح. نداش كوبسف يونيو 7 10 في 10:43 إذا كنت تقوم بتشغيل بيئة الإنتاج مع عدم وجود مساحة كافية لتكرار كل ما تبذلونه من الجداول، وأعتقد أن كنت تبحث عن المتاعب عاجلا أو آجلا. إذا قمت بتوفير بعض المعلومات حول عدد الصفوف مع someOtherColumn1، ربما يمكننا أن نفكر طريقة أخرى، ولكن أقترح: 0) النسخ الاحتياطي الجدول الخاص بك 1) فهرس العمود العلم 2) تعيين الخيار الجدول إلى أي سجل. إذا بوسيبل 3) كتابة الإجراء المخزن لتشغيل التحديثات أجاب يونيو 2 10 في 3:17 بتو. أنت ذاهب إلى الحاجة لتشغيل هذا الإجراء أكثر من مرة في الحياة نداش الدكتور بيليساريوس يونيو 2 10 في 3:24 كيف يمكنك تعيين خيار الجدول إلى سجل كوتنو ترانديكتيونسكوت نداش user356004 جون 7 10 في 9:56 إجابتك 2017 المكدس الصرف ، تحتاج إنسي لحساب مبلغ متجدد خلال نطاق زمني. لتوضيح، وذلك باستخدام قاعدة بيانات عينة أدفنتوروركس. فإن بناء جملة افتراضية التالية تفعل بالضبط ما أحتاج إليه: للأسف، لا يسمح الإطار إطار الإطار رانج حاليا فاصل في سكل سيرفر. أعرف أنني يمكن أن أكتب حل باستخدام استعلام فرعي وتجميع العادية (غير نافذة): وبالنظر إلى الفهرس التالي: خطة التنفيذ هي: في حين ليست فعالة بشكل فظيع، يبدو أنه ينبغي أن يكون من الممكن التعبير عن هذا الاستعلام باستخدام فقط نافذة تجميع ووظائف تحليلية معتمدة في سكل سيرفر 2012، 2014، أو 2016 (حتى الآن). للتوضيح، أبحث عن حل يقوم بتمرير واحد على البيانات. في T-سكل هذا من المرجح أن يعني أن العبارة أوفر ستؤدي العمل، وستتضمن خطة التنفيذ وحدات التخزين المؤقت للنافذة ومجمعات النافذة. جميع عناصر اللغة التي تستخدم شرط أوفر هي لعبة عادلة. الحل سككلر هو مقبول، شريطة أن يكون مضمونا لإنتاج النتائج الصحيحة. للحصول على حلول T-سكل، وعدد أقل من تجزئة، نوع، ونفايات التخزين المؤقت في خطة التنفيذ، كلما كان ذلك أفضل. لا تتردد في إضافة فهارس، ولكن لا يسمح بهياكل منفصلة (لذلك لا توجد جداول محسوبة مسبقا متزامنة مع مشغلات، على سبيل المثال). يسمح الجداول المرجعية (جداول الأرقام والتواريخ وما إلى ذلك) من الناحية المثالية، والحلول تنتج بالضبط نفس النتائج في نفس الترتيب مثل إصدار الاستعلام الفرعي أعلاه، ولكن أي شيء يمكن القول صحته هو أيضا مقبولة. الأداء هو دائما الاعتبار، لذلك يجب أن تكون الحلول على الأقل كفاءة معقولة. غرفة دردشة مخصصة: لقد أنشأت غرفة دردشة عامة للمناقشات المتعلقة بهذا السؤال وإجاباته. يمكن لأي مستخدم لديه 20 نقطة سمعة على الأقل المشاركة مباشرة. يرجى بينغ لي في تعليق أدناه إذا كان لديك أقل من 20 مندوب وترغب في المشاركة. سأل 7 سبتمبر 15 في 20:13 السؤال الكبير، بول لقد استخدمت نهجين مختلفين، واحد في T - سكل واحد في كلر. يمكن تلخيص نهج T-سكل كخطوات التالية: خذ المنتج المتقاطع ل برودوكتسديتس دمج في بيانات المبيعات الملحوظة تجميع البيانات إلى مستوى برودوكتديت حساب المبالغ المتداولة خلال ال 45 يوما الماضية استنادا إلى هذه البيانات المجمعة (التي تحتوي على أي الأيام المفقودة شغل في) تصفية تلك النتائج فقط الاقتران برودوكتديت التي كان واحد أو أكثر من المبيعات باستخدام إحصائيات مجموعة إو أون. هذا النهج تقارير الجدول ترانزاكتيونهيستوري. مسح عدد 1، منطقي يقرأ 484. الذي يؤكد مرور واحد على الطاولة. كمرجع، تقارير الاستعلام حلقة البحث الأصلية الجدول ترانزاكتيونهيستوري. مسح عدد 113444، منطقي يقرأ 438366. كما ذكرت من قبل مجموعة احصائيات الوقت على. وقت وحدة المعالجة المركزية هو 514ms. يقارن هذا بشكل إيجابي إلى 2231ms لطلب البحث الأصلي. يمكن تلخيص ملخص كلر على النحو التالي: قراءة البيانات إلى الذاكرة، التي أمر بها المنتج والتاريخ أثناء معالجة كل معاملة، إضافة إلى مجموع تشغيل التكاليف. عندما تكون المعاملة عبارة عن منتج مختلف عن المعاملة السابقة، قم بإعادة تعيين المجموع الإجمالي إلى 0. الحفاظ على مؤشر إلى المعاملة الأولى التي لها نفس (المنتج والتاريخ) كعملية الحالية. كلما واجهت آخر معاملة مع ذلك (المنتج والتاريخ)، وحساب المبلغ المتداول لتلك الصفقة وتطبيقه على جميع المعاملات مع نفسه (المنتج والتاريخ) عودة كافة النتائج للمستخدم باستخدام مجموعة إحصائيات إو أون. هذا النهج التقارير التي لم يحدث إو منطقي نجاح باهر، وهو الحل الأمثل (في الواقع، يبدو أن مجموعة إحصائيات إو لا يبلغ إو تكبدها داخل كلر، ولكن من التعليمات البرمجية، فمن السهل أن نرى أن يتم إجراء مسح واحد فقط من الجدول واسترجاع البيانات في الترتيب من قبل مؤشر اقترح بول كما ذكرت من قبل إحصائيات مجموعة الوقت على وقت وحدة المعالجة المركزية هو الآن 187ms، لذلك هذا هو تماما تحسن على نهج سكل T. للأسف، فإن الوقت المنقضي العام لكلا النهجين هو في حين أن كلر يستند إلى نهج لا بد من إخراج 113K الصفوف إلى وحدة التحكم (مقابل 52K فقط ل T - سكل النهج التي مجموعات حسب برودوكتديت)، لذلك هذا السبب لماذا ركزت إيف على وقت وحدة المعالجة المركزية بدلا من ذلك وهناك ميزة كبيرة أخرى من هذا النهج هو أنه يعطي بالضبط نفس النتائج مثل النهج لوبزيك الأصلي، بما في ذلك صف لكل معاملة حتى في الحالات التي تباع فيها منتج عدة مرات في نفس اليوم. (على أدفنتوروركس، وأنا على وجه التحديد مقارنة الصف عن طريق صف إعادة وأكدت أنها تربط مع بولس الاستعلام الأصلي.) عيب هذا النهج، على الأقل في شكله الحالي، هو أنه يقرأ جميع البيانات في الذاكرة. ومع ذلك، فإن الخوارزمية التي تم تصميمها فقط يحتاج بدقة إطار الإطار الحالي في الذاكرة في أي وقت معين ويمكن تحديثها للعمل لمجموعات البيانات التي تتجاوز الذاكرة. وقد أوضح بول هذه النقطة في جوابه عن طريق تنفيذ تنفيذ هذه الخوارزمية التي تخزن فقط نافذة انزلاق في الذاكرة. ويأتي هذا على حساب منح أذونات أعلى إلى الجمعية كلر، ولكن سيكون بالتأكيد جديرة بالاهتمام في توسيع نطاق هذا الحل حتى مجموعات البيانات الكبيرة بشكل تعسفي. T-سكل - مسح واحد، مجمعة حسب التاريخ خطة التنفيذ من خطة التنفيذ، نرى أن الفهرس الأصلي الذي اقترحه بول يكفي للسماح لنا بإجراء مسح واحد أمر من Production. TransactionHistory. باستخدام دمج دمج إلى الجمع بين تاريخ المعاملة مع كل مجموعة برودوكتديت الممكنة. هناك عدد قليل من الافتراضات الهامة المخبزة في هذا النهج. أفترض أنه سيكون متروكا لبول لتحديد ما إذا كانت مقبولة :) أنا باستخدام الجدول Product. Product. هذا الجدول متاح مجانا على AdventureWorks2012 ويتم فرض العلاقة من قبل مفتاح أجنبي من Production. TransactionHistory. لذلك فسرتها على أنها لعبة عادلة. ويعتمد هذا النهج على حقيقة أن المعاملات ليس لديها عنصر الوقت على AdventureWorks2012 إذا فعلوا ذلك، وتوليد مجموعة كاملة من مجموعات برودوكتديت لم يعد ممكنا من دون أخذ أول مرور على تاريخ الصفقة. أنا إنتاج روزيت الذي يحتوي على صف واحد فقط لكل زوج برودوكتديت. وأعتقد أن هذا يمكن القول أنه صحيح وفي كثير من الحالات نتيجة أكثر من المرغوب فيه للعودة. لكل منتج، أضفت عمود نوموردرز للإشارة إلى عدد المبيعات التي حدثت. انظر لقطة الشاشة التالية لمقارنة نتائج الاستعلام الأصلي مقابل الاستعلام المقترح في الحالات التي تم فيها بيع منتج عدة مرات في نفس التاريخ (على سبيل المثال: 319 2007-09-05 00: 00: 00.000) كلر - وان سكان ، مجموعة نتائج غير مجمعة كاملة الجسم وظيفة الرئيسي ليس هناك طن لرؤية هنا الجسم الرئيسي من وظيفة يعلن المدخلات (التي يجب أن تتطابق مع وظيفة سكل المقابلة)، ويحدد اتصال سكل، ويفتح سكلريدر. إيف فصلت المنطق الرئيسي بحيث يكون من الأسهل للتركيز على: المنطق التالي يمكن أن تكون مكتوبة مضمنة، ولكن من الأسهل قليلا لقراءة عندما يتم تقسيمها إلى أساليبها الخاصة. ربط كل ذلك معا في سكل كان كل شيء حتى هذه النقطة في C، لذلك يتيح رؤية سكل المعنية المعنية. (بدلا من ذلك، يمكنك استخدام هذا البرنامج النصي نشر لإنشاء التجمع مباشرة من بت تجميع بلدي بدلا من تجميع نفسك.) نهج كلر يوفر الكثير من المرونة لتحسين الخوارزمية، وربما يمكن ضبطها أكثر من ذلك من قبل خبير في C. ومع ذلك، هناك أيضا سلبيات لاستراتيجية كلر. بعض الأشياء التي يجب مراعاتها: يحتفظ نهج كلر هذا بنسخة من مجموعة البيانات في الذاكرة. فمن الممكن استخدام نهج تدفق، ولكن واجهت صعوبات الأولية ووجدت أن هناك مشكلة اتصال المعلقة يشكو من أن التغييرات في سكل 2008 تجعل من الصعب استخدام هذا النوع من النهج. لا يزال ممكنا (كما يوضح بول)، ولكن يتطلب مستوى أعلى من الأذونات عن طريق وضع قاعدة البيانات كما موثوق ومنح إكسترنالاشيس إلى الجمعية كلر. لذلك هناك بعض المتاعب والآثار الأمنية المحتملة، ولكن العائد هو نهج تدفق التي يمكن أن نطاق أفضل إلى مجموعات البيانات أكبر بكثير من تلك الموجودة على أدفنتوروركس. قد يكون كلر أقل قابلية للوصول لبعض ديسيبلز، مما يجعل هذه الوظيفة أكثر من مربع أسود ليست شفافة، وليس بسهولة تعديلها، وليس بسهولة نشرها، وربما ليس بسهولة تصحيحها. هذا هو عيب كبير جدا بالمقارنة مع نهج سكل T. المكافأة: T-سكل 2 - النهج العملي إد في الواقع استخدام بعد محاولة التفكير في المشكلة بشكل خلاق لفترة من الوقت، اعتقدت إد أيضا نشر بطريقة بسيطة إلى حد ما، العملية التي من المحتمل أن تختار لمعالجة هذه المشكلة إذا جاء في عملي اليومي. وهو يستفيد من وظائف إطار سكل 2012، ولكن ليس في نوع من الطريقة الرائدة التي كان السؤال يأمل في: هذا يعطي في الواقع خطة استعلام شاملة بسيطة إلى حد ما، حتى عند النظر في كل من خطتي الاستعلام ذات الصلة معا: عدد قليل الأسباب التي أعجبها هذا النهج: فهو ينتج النتيجة الكاملة المحددة في بيان المشكلة (على عكس معظم حلول T-سكل الأخرى التي تعيد نسخة مجمعة من النتائج). فمن السهل أن نفهم، وفهم، والتصحيح أنا لن يعود مرة أخرى في وقت لاحق في وقت لاحق، وتساءل كيف هيك يمكنني إجراء تغيير صغير دون تخريب صحتها أو أدائها يعمل في حوالي 900ms على مجموعة البيانات المقدمة، بدلا من 2700ms من الحلقة الأصلية إذا كانت البيانات أكثر كثافة (المزيد من المعاملات في اليوم الواحد)، فإن التعقيد الحسابي لا ينمو تربويا مع عدد من المعاملات في نافذة انزلاق (كما يفعل الاستعلام الأصلي) وأعتقد أن هذا يعالج جزءا من بولس قلق حول أراد تجنب تفحص متعددة ويؤدي في الأساس لا يوجد تيمبدب إو في التحديثات الأخيرة من سكل 2012 بسبب وظيفة جديدة تيمبدب كسول الكتابة مجموعات البيانات كبيرة جدا، فمن تافهة لتقسيم العمل إلى دفعات منفصلة لكل منتج إذا كان ضغط الذاكرة لتصبح مصدر قلق اثنين من المحاذير المحتملة: في حين أنه من الناحية الفنية لا تفحص Production. TransactionHistory مرة واحدة فقط، وليس حقا نهج مسح واحد لأن الجدول تيمب من حجم مماثل وسوف تحتاج إلى أداء إو لوجيسيون إضافية على هذا الجدول كذلك. ومع ذلك، أنا لا أرى هذا مختلفا جدا عن طاولة العمل التي لدينا المزيد من التحكم اليدوي منذ أن حددنا هيكلها الدقيق اعتمادا على البيئة الخاصة بك، ويمكن النظر إلى استخدام تمبدب على أنها إيجابية (على سبيل المثال على مجموعة منفصلة من محركات الأقراص الصلبة) أو سلبية (التزامن عالية على الخادم، والكثير من تمبدب خلاف بالفعل) أجاب 8 سبتمبر 15 في 15:41 هذا هو إجابة طويلة، لذلك قررت إضافة ملخص هنا. في البداية أقدم الحل الذي ينتج بالضبط نفس النتيجة في نفس الترتيب كما في السؤال. فإنه يقوم بمسح الجدول الرئيسي 3 مرات: للحصول على قائمة برودكتيدس مع مجموعة من التواريخ لكل منتج، ملخص تكاليف كل يوم (لأن هناك عدة معاملات بنفس التواريخ)، للانضمام النتيجة مع الصفوف الأصلية. التالي أقارن بين اثنين من النهج التي تبسيط المهمة وتجنب واحد آخر مسح من الجدول الرئيسي. ونتائجها هي ملخص يومي، بمعنى أنه إذا كانت هناك عدة معاملات على منتج لها نفس التاريخ يتم طرحها في صف واحد. نهجي من الخطوة السابقة بفحص الجدول مرتين. نهج جيوف باترسون بمسح الجدول مرة واحدة، لأنه يستخدم المعرفة الخارجية حول مجموعة من التواريخ وقائمة المنتجات. في الماضي أقدم حل تمرير واحد أن يعود مرة أخرى ملخص اليومي، لكنه لا يتطلب معرفة خارجية حول مجموعة من التواريخ أو قائمة برودكتيدس. سأستخدم قاعدة بيانات AdventureWorks2014 و سكل سيرفر إكسبريس 2014. التغييرات على قاعدة البيانات الأصلية: نوع متغير من Production. TransactionHistory. TransactionDate من داتيتيم حتى الآن. وكان عنصر الوقت صفر على أي حال. وأضاف جدول التقويم dbo. Calendar وأضاف مؤشر ل Production. TransactionHistory مسن مقالة حول شرط أوفر لديه ارتباط إلى مشاركة بلوق ممتازة حول وظائف النافذة من قبل إيتزيك بن غان. في هذا المنصب يشرح كيف يعمل أوفر، والفرق بين روز وخيارات رانج ويذكر هذه المشكلة جدا لحساب مجموع المتداول على مدى التاريخ. ويذكر أن الإصدار الحالي من سكل سيرفر لا تنفذ رانج بالكامل ولا تنفذ أنواع البيانات الفاصلة الزمنية. أعطاني شرحا للفرق بين روز و رانج فكرة. التواريخ بدون ثغرات وتكرارات إذا كان جدول ترانزاكتيونهيستوري يحتوي على تواريخ بدون ثغرات ودون تكرار، فإن الاستعلام التالي سيؤدي إلى نتائج صحيحة: في الواقع، ستغطي نافذة من 45 صفا 45 يوما بالضبط. التواريخ التي تحتوي على ثغرات بدون نسخ مكررة لسوء الحظ، تحتوي بياناتنا على ثغرات في التواريخ. لحل هذه المشكلة يمكننا استخدام جدول التقويم لتوليد مجموعة من التواريخ دون ثغرات، ثم ليفت الانضمام إلى البيانات الأصلية إلى هذه المجموعة واستخدام نفس الاستعلام مع صفوف بين 45 بريسينغ أند كيرنت رو. وهذا من شأنه أن ينتج نتائج صحيحة فقط إذا لم يتم تكرار التواريخ (ضمن برودكتيد نفسه). التواريخ مع وجود ثغرات مع التكرارات لسوء الحظ، لدينا بيانات على حد سواء ثغرات في التواريخ والتواريخ يمكن تكرار داخل برودكتيد نفسه. لحل هذه المشكلة يمكننا غروب البيانات الأصلية بواسطة برودكتيد، ترانزاكتيوندات لتوليد مجموعة من التواريخ دون التكرارات. ثم استخدم جدول التقويم لإنشاء مجموعة من التواريخ بدون ثغرات. ثم يمكننا استخدام الاستعلام مع روز بين 45 بريسينغ و رو الحالي لحساب المتداول سوم. وهذا من شأنه أن يحقق نتائج صحيحة. انظر التعليقات في الاستعلام أدناه. وأكدت أن هذا الاستعلام ينتج نفس النتائج مثل النهج من السؤال الذي يستخدم الاستعلام الفرعي. يستخدم الاستعلام الأول الاستعلام الفرعي، ثانيا - هذا النهج. يمكنك أن ترى أن مدة وعدد من يقرأ هو أقل بكثير في هذا النهج. معظم التكاليف المقدرة في هذا النهج هو أوردر بي النهائي. انظر أدناه. نهج الاستعلام الفرعي لديه خطة بسيطة مع حلقات متداخلة والتعقيد O (ن). خطة لهذا النهج بفحص ترانزاكتيونيستوري عدة مرات، ولكن لا توجد حلقات. كما يمكنك أن ترى أكثر من 70 من التكلفة المقدرة هو فرز ل أوردر بي النهائي. أهم نتيجة - طلب بحث. أسفل - أوفر. تجنب مسح إضافي آخر مؤشر المسح الضوئي، دمج دمج وترتيب في الخطة أعلاه هو سبب النهائي إنر جوين مع الجدول الأصلي لجعل النتيجة النهائية بالضبط نفس النهج بطيئة مع الاستعلام الفرعي. عدد الصفوف التي تم إرجاعها هو نفسه في جدول ترانزاكتيونهيستوري. هناك صفوف في ترانزاكتيونيستوري عندما وقعت العديد من المعاملات في نفس اليوم لنفس المنتج. إذا كان لا بأس لإظهار ملخص يومي فقط في النتيجة، ثم يمكن إزالة هذا جوين النهائي والاستعلام يصبح أبسط قليلا وأسرع قليلا. يتم استبدال آخر مؤشر المسح الضوئي، دمج دمج وترتيب من الخطة السابقة مع تصفية، مما يزيل الصفوف التي أضيفت بواسطة التقويم. ومع ذلك، يتم فحص ترانزاكتيونيستوري مرتين. وهناك حاجة إلى مسح إضافي واحد للحصول على مجموعة من التواريخ لكل منتج. كنت مهتما لمعرفة كيف يقارن مع نهج آخر، حيث نستخدم المعرفة الخارجية حول النطاق العالمي للتمور في ترانزاكتيونيستوري. بالإضافة إلى جدول إضافي المنتج الذي يحتوي على كافة برودكتيدس لتجنب إجراء مسح إضافي. قمت بإزالة حساب عدد المعاملات في اليوم من هذا الاستعلام لجعل المقارنة صالحة. ويمكن أن تضاف في كل من الاستفسارات، ولكن معرف ترغب في الاحتفاظ بها بسيطة للمقارنة. كان لي أيضا لاستخدام تواريخ أخرى، لأنني استخدام 2014 نسخة من قاعدة البيانات. كل من الاستعلامات إرجاع نفس النتيجة في نفس الترتيب. وهنا الوقت وإحصاءات إو. البديل اثنين المسح الضوئي هو أسرع قليلا ولها أقل يقرأ، لأن واحد المسح البديل لديه لاستخدام المنضدة الكثير. الى جانب ذلك، واحد المسح البديل يولد المزيد من الصفوف من الحاجة كما ترون في الخطط. فإنه يولد التواريخ لكل برودوكتيد الموجود في جدول المنتج، حتى إذا لم يكن برودكتيد أي معاملات. هناك 504 صفوف في جدول المنتج، ولكن فقط 441 المنتجات لها معاملات في ترانزاكتيونهيستوري. أيضا، فإنه يولد نفس مجموعة من التواريخ لكل منتج، وهو أكثر من اللازم. إذا كان لدى ترانزاكتيونهيستوري تاريخا عاما أطول، مع وجود تاريخ قصير نسبيا لكل منتج على حدة، فإن عدد الصفوف الإضافية غير الضرورية سيكون أعلى من ذلك. من ناحية أخرى، فمن الممكن لتحسين اثنين من المسح البديل أكثر قليلا من خلال إنشاء آخر، مؤشر أكثر ضيقا على فقط (برودكتيد، ترانزاكتيونديت). سيتم استخدام هذا المؤشر لحساب تواريخ ستارتند لكل منتج (كتيبرودوكتس) وسيكون له صفحات أقل من مؤشر التغطية ونتيجة لذلك يسبب قراءة أقل. لذلك، يمكننا أن نختار، إما أن يكون مسح بسيط إضافي صريح، أو لديك المنضدة الضمنية. راجع للشغل، إذا كان من المستحسن أن يكون نتيجة مع ملخصات يومية فقط، فمن الأفضل لإنشاء فهرس لا يتضمن ريفيرانسوردريد. فإنه سيتم استخدام صفحات أقل أقل إو. حل تمرير واحد باستخدام كروس تطبيق يصبح إجابة طويلة حقا، ولكن هنا هو واحد أكثر البديل الذي يعود ملخص يومي فقط مرة أخرى، لكنه لا مسح واحد فقط من البيانات وأنها لا تتطلب معرفة خارجية حول مجموعة من التواريخ أو قائمة برودكتيدس. فإنه لا تفعل أنواع وسيطة كذلك. الأداء العام مشابه للمتغيرات السابقة، على الرغم من أنه يبدو أسوأ قليلا. الفكرة الرئيسية هي استخدام جدول أرقام لتوليد الصفوف التي من شأنها سد الثغرات في التواريخ. لكل تاريخ موجود استخدام ليد لحساب حجم الفجوة في أيام ثم استخدام كروس تطبيق لإضافة العدد المطلوب من الصفوف في مجموعة النتائج. في البداية حاولت ذلك مع جدول دائم من الأرقام. وأظهرت الخطة عددا كبيرا من القراءات في هذا الجدول، على الرغم من أن المدة الفعلية كانت إلى حد كبير نفسها، كما عندما ولدت أرقام على الطاير باستخدام كت. هذه الخطة أطول، لأن الاستعلام يستخدم دورتين نافذة (ليد و سوم). حل سكلكل بديل أن ينفذ بشكل أسرع ويتطلب ذاكرة أقل: وهذا يتطلب إذن إكسترنالاشيس لأنه يستخدم اتصال الاسترجاع إلى الملقم الهدف وقاعدة البيانات بدلا من اتصال السياق (بطيء). هذه هي كيفية استدعاء الدالة: تنتج بالضبط نفس النتائج، في نفس الترتيب، والسؤال. يقرأ منطقي منشئ ملفات التعريف: 481 الميزة الرئيسية لهذا التنفيذ هو أنه أسرع من استخدام اتصال السياق، ويستخدم ذاكرة أقل. أنها تبقي فقط شيئين في الذاكرة في أي وقت واحد: أي الصفوف مكررة (نفس المنتج وتاريخ المعاملة). وهذا مطلوب لأنه حتى يتغير المنتج أو التاريخ، ونحن لا نعرف ما سيكون مجموع المبلغ النهائي. في بيانات العينة، هناك مجموعة واحدة من المنتج والتاريخ يحتوي على 64 صف. انزلاق 45 يوما مجموعة من التكلفة والمعاملات مواعيد فقط، للمنتج الحالي. هذا ضروري لضبط مجموع تشغيل بسيط للصفوف التي تترك نافذة انزلاق 45 يوما. هذا التخزين المؤقت الحد الأدنى يجب التأكد من هذا الأسلوب المقاييس بشكل جيد بالتأكيد أفضل من محاولة لعقد المدخلات كلها مجموعة في الذاكرة كلر. إذا كنت تستخدم إصدار 64 بت المؤسسة أو المطور أو التقييم من سكل سيرفر 2014 يمكنك استخدام في الذاكرة أولتب. الحل لن يكون مسح واحد، وسوف بالكاد استخدام أي وظائف نافذة على الإطلاق ولكن قد تضيف بعض القيمة لهذا السؤال والخوارزمية المستخدمة يمكن أن تستخدم إلهام إلى حلول أخرى. أولا تحتاج إلى تمكين أوليمب في الذاكرة على قاعدة بيانات أدفنتوروركس. المعلمة إلى الإجراء هو متغير الجدول في الذاكرة والتي يجب أن تعرف كنوع. معرف ليست فريدة من نوعها في هذا الجدول، فهي فريدة من نوعها لكل مجموعة من برودكتيد و ترانزاكتيونديت. هناك بعض التعليقات في الإجراء الذي يقول لك ما يفعله ولكن بشكل عام فإنه يتم حساب إجمالي تشغيل في حلقة ولكل التكرار فإنه يقوم بالبحث عن المجموع تشغيل كما كان قبل 45 يوما (أو أكثر). مجموع التشغيل الحالي ناقص مجموع تشغيل كما كان قبل 45 يوما هو المتداول 45 يوما المبلغ الذي نبحث عنه. استدعاء الإجراء من هذا القبيل. اختبار هذا على جهاز الكمبيوتر تقارير العميل تقارير إجمالي وقت التنفيذ حوالي 750 ميلي ثانية. للمقارنات، يستغرق إصدار الاستعلام الفرعي 3.5 ثوان. ويمكن أيضا أن تستخدم هذه الخوارزمية من قبل سكل T العادية. احسب إجمالي التشغيل، باستخدام نطاق غير صفوف، وتخزين النتيجة في جدول مؤقت. ثم يمكنك الاستعلام عن هذا الجدول مع النفس الانضمام إلى مجموع تشغيل كما كان قبل 45 يوما وحساب المبلغ المتداول. ومع ذلك، فإن تنفيذ النطاق مقارنة بالصفوف بطيء جدا بسبب حقيقة أن هناك حاجة لعلاج التكرارات من النظام حسب البند بشكل مختلف لذلك لم أحصل على كل هذا الأداء الجيد مع هذا النهج. يمكن أن يكون الحل إلى ذلك استخدام وظيفة نافذة أخرى مثل لاستفالو () على إجمالي تشغيل محسوب باستخدام صفوف لمحاكاة نطاق تشغيل المجموع. طريقة أخرى هي استخدام ماكس () على (). كلاهما لديه بعض القضايا. العثور على الفهرس المناسب لاستخدامه لتجنب الأنواع وتجنب التخزين المؤقت مع الحد الأقصى () فوق () الإصدار. تخلى عن تحسين تلك الأشياء ولكن إذا كنت مهتما في رمز لدي حتى الآن واسمحوا لي أن أعرف. أجاب 15 سبتمبر 15 في 12:38 حسنا أن كان متعة :) حل بلدي هو أبطأ قليلا من جيوفاترسونس ولكن جزء من هذا هو حقيقة أن إم ربط العودة إلى الجدول الأصلي من أجل القضاء على واحدة من افتراضات جيفس (أي صف واحد لكل زوج برودوكتديت). ذهبت مع الافتراض كان هذا هو نسخة مبسطة من الاستعلام النهائي وقد تتطلب معلومات إضافية من الجدول الأصلي. ملاحظة: إم الاقتراض جدول تقويم جيوفس وفي الواقع انتهى الأمر مع حل مماثل جدا: هنا هو الاستعلام نفسه: أساسا قررت أن أسهل طريقة للتعامل معها كان استخدام الخيار لروز البند. ولكن ذلك يتطلب أن يكون لدي صف واحد فقط لكل برودوكتيد. مجموعة ترانزاكتيوندات وليس ذلك فحسب، ولكن كان لي أن يكون صف واحد لكل برودكتيد والتاريخ الممكن. فعلت ذلك الجمع بين جداول المنتج والتقويم و ترانزاكتيونهيستوري في كت. ثم اضطررت إلى إنشاء كت أخرى لتوليد المعلومات المتداول. اضطررت إلى القيام بذلك لأنه إذا انضممت إلى الوراء الجدول الأصلي مباشرة حصلت على القضاء الصف الذي ألقى قبالة نتائجي. بعد ذلك كان الأمر بسيطا في الانضمام كتفي الثاني مرة أخرى إلى الجدول الأصلي. فعلت إضافة العمود تب (ليتم القضاء عليها) للتخلص من الصفوف الفارغة التي تم إنشاؤها في كتس. كما استخدمت تطبيق كروس في كت الأولية لإنشاء حدود لجدول التقويم الخاص بي. ثم قمت بإضافة الفهرس الموصى به: وحصلت على خطة التنفيذ النهائي: إديت: في النهاية أضفت فهرسا على جدول التقويم الذي رفع الأداء بهامش معقول. أجاب سيب 10 15 في 16:34 لدي عدد قليل من الحلول البديلة التي لا تستخدم الفهارس أو الجداول المرجعية. ربما يمكن أن تكون مفيدة في الحالات التي لم يكن لديك الوصول إلى أي جداول إضافية ولا يمكن إنشاء فهارس. يبدو أنه من الممكن الحصول على النتائج الصحيحة عند التجميع بواسطة ترانزاكتيوندات مع مجرد تمريرة واحدة من البيانات و مجرد وظيفة نافذة واحدة. ومع ذلك، لم أستطع معرفة طريقة للقيام بذلك مع وظيفة نافذة واحدة فقط عندما لا يمكنك تجميع بواسطة ترانزاكتيونديت. لتوفير إطار مرجعي، على الجهاز بلدي الحل الأصلي نشر في السؤال لديه وحدة المعالجة المركزية الوقت من 2808 مللي ثانية دون مؤشر تغطية و 1950 مللي ثانية مع مؤشر التغطية. أنا اختبار مع قاعدة بيانات AdventureWorks2014 و سكل سيرفر إكسبريس 2014. دعونا نبدأ مع حل عندما يمكننا مجموعة من قبل ترانزاكتيونديت. يمكن أيضا التعبير عن مبلغ جار خلال الأيام X الماضية بالطريقة التالية: تشغيل مجموع صف تشغيل مجموع الصفوف السابقة - تشغيل مجموع كل الصفوف السابقة التي يكون التاريخ خارج إطار التاريخ. في سكل، طريقة واحدة للتعبير عن ذلك عن طريق جعل نسختين من البيانات الخاصة بك وللنسخة الثانية، ضرب التكلفة بنسبة -1 وإضافة X1 أيام إلى عمود التاريخ. سوف حساب مجموع التوالي على جميع البيانات تنفيذ الصيغة أعلاه. سوء عرض هذا لبعض البيانات المثال. في ما يلي بعض تاريخ العينة ل برودكتيد واحد. أنا أمثل التواريخ كأرقام لجعل الحسابات أسهل. بدء البيانات: إضافة في نسخة ثانية من البيانات. النسخة الثانية يحتوي على 46 يوما تضاف إلى التاريخ والتكلفة مضروبة في -1: اتخاذ مبلغ تشغيل أمر حسب التاريخ تصاعدي و كوبيدرو تنازلي: تصفية الصفوف المنسوخة للحصول على النتيجة المرجوة: سكل التالية هي طريقة واحدة لتنفيذ فوق خوارزمية: على الجهاز الخاص بي أخذ هذا 702 مللي ثانية من الوقت وحدة المعالجة المركزية مع مؤشر التغطية و 734 مللي ثانية من وقت وحدة المعالجة المركزية دون الفهرس. يمكن العثور على خطة الاستعلام هنا: برينتوزارباستيثبلانيدسجدسغفسل جانب واحد من هذا الحل هو أن هناك يبدو أن هناك نوع لا مفر منه عند الطلب من قبل عمود عملية جديدة. أنا لا أعتقد أن هذا النوع يمكن حلها عن طريق إضافة فهارس لأننا بحاجة إلى الجمع بين نسختين من البيانات قبل القيام بالترتيب. كنت قادرا على التخلص من نوع في نهاية الاستعلام عن طريق إضافة في عمود مختلف إلى أوردر بي. إذا أمرت من قبل فيلتيرفلاغ وجدت أن سكل سيرفر من شأنه أن يحسن من هذا العمود من نوع وسوف يؤدي نوع صريح. كانت الحلول عند الحاجة إلى إعادة نتيجة مجموعة مع قيم تكرار المعاملة لنفس برودوكتيد أكثر تعقيدا بكثير. وأود أن تلخيص المشكلة في وقت واحد تحتاج إلى تقسيم من قبل نفس العمود. بناء الجملة التي قدمها بول حل هذه المسألة بحيث ليس من المستغرب أن من الصعب جدا للتعبير عن وظائف النافذة الحالية المتوفرة في سكل سيرفر (إذا كان واسنت من الصعب التعبير عن لن تكون هناك حاجة لتوسيع بناء الجملة). إذا كنت تستخدم الاستعلام أعلاه دون تجميع ثم أحصل على قيم مختلفة للمجموع المتداول عندما يكون هناك صفوف متعددة مع نفس برودوكتيد و ترانزاكتيونديت. طريقة واحدة لحل هذا هو أن تفعل نفس حساب مجموع التوالي كما هو موضح أعلاه ولكن أيضا للعلم الصف الأخير في القسم. ويمكن القيام بذلك مع ليد (على افتراض برودكتيد أبدا نول) دون نوع إضافي. بالنسبة لقيمة مجموع التشغيل النهائية، استخدم ماكس كدالة نافذة لتطبيق القيمة في الصف الأخير من القسم إلى كافة الصفوف في القسم. على الجهاز الخاص بي أخذ هذا 2464ms من وقت وحدة المعالجة المركزية دون مؤشر التغطية. كما كان من قبل يبدو أن هناك نوعا لا مفر منه. خطة الاستعلام يمكن العثور عليها هنا: برينتوزارباستيبلانيدهيوسغفبل أعتقد أن هناك مجالا للتحسين في الاستعلام أعلاه. There are certainly other ways to use windows functions to get the desired result. Most people are familiar with the phrase, quotthis will kill two birds with one stonequot. If you39re not, the phase refers to an approach that addresses two objectives in one action. (Unfortunately, the expression itself is rather unpleasant, as most of us don39t want to throw stones at innocent animals) Today I39m going to cover some basics on two great features in SQL Server: the Columnstore index (available only in SQL Server Enterprise) and the SQL Query Store . Microsoft actually implemented the Columnstore index in SQL 2012 Enterprise, though they39ve enhanced it in the last two releases of SQL Server. Microsoft introduced the Query Store in SQL Server 2016. So, what are these features and why are they important Well, I have a demo that will introduce both features and show how they can help us. Before I go any further, I also cover this (and other SQL 2016 features) in my CODE Magazine article on new features SQL 2016. As a basic introduction, the Columnstore index can help speed up queries that scanaggregate over large amounts of data, and the Query Store tracks query executions, execution plans, and runtime statistics that you39d normally need to collect manually. Trust me when I say, these are great features. For this demo, I39ll be using the Microsoft Contoso Retail Data Warehouse demo database. Loosely speaking, Contoso DW is like quota really big AdventureWorksquot, with tables containing millions of rows. (The largest AdventureWorks table contains roughly 100,000 rows at most). You can download the Contoso DW database here: microsoften-usdownloaddetails. aspxid18279. Contoso DW works very well when you want to test performance on queries against larger tables. Contoso DW contains a standard data warehouse Fact table called FactOnLineSales, with 12.6 million rows. That39s certainly not the largest data warehouse table in the world, but it39s not child39s play either. Suppose I want to summarize product sales amount for 2009, and rank the products. I might query the fact table and join to the Product Dimension table and use a RANK function, like so: Here39s a partial result set of the top 10 rows, by Total Sales. On my laptop (i7, 16 GB of RAM), the query takes anywhere from 3-4 seconds to run. That might not seem like the end of the world, but some users might expect near-instant results (the way you might see near-instant results when using Excel against an OLAP cube). The only index I currently have on this table is a clustered index on a sales key. If I look at the execution plan, SQL Server makes a suggestion to add a covering index to the table: Now, just because SQL Server suggests an index, doesn39t mean you should blindly create indexes on every quotmissing indexquot message. However, in this instance, SQL Server detects that we are filtering based on year, and using the Product Key and Sales Amount. So, SQL Server suggests a covering index, with the DateKey as the index key field. The reason we call this a quotcoveringquot index is because SQL Server will quotbring along the non-key fieldsquot we used in the query, quotfor the ridequot. That way, SQL Server doesn39t need to use the table or the clustered index at all the database engine can simply use the covering index for the query. Covering indexes are popular in certain data warehousing and reporting database scenarios, though they do come at a cost of the database engine maintaining them. Note: Covering indexes have been around for a long time, so I haven39t yet covered the Columnstore index and the Query Store. So, I will add the covering index: If I re-execute the same query I ran a moment ago (the one that aggregated the sales amount for each product), the query sometimes seems to run about a second faster, and I get a different execution plan, one that uses an Index Seek instead of an Index Scan (using the date key on the covering index to retrieve sales for 2009). So, prior to the Columnstore Index, this could be one way to optimize this query in much older versions of SQL Server. It runs a little faster than the first one, and I get an execution plan with an Index Seek instead of an Index Scan. However, there are some issues: The two execution operators quotIndex Seekquot and quotHash Match (Aggregate)quot both essentially operate quotrow by rowquot. Imagine this in a table with hundreds of millions of rows. Related, think about the contents of a fact table: in this case, a single date key value andor a single product key value might be repeated across hundreds of thousands of rows (remember, the fact table also has keys for geography, promotion, salesman, etc.) So, when the quotIndex Seekquot and quotHash Matchquot work row by row, they are doing so over values that might be repeated across many other rows. This is normally where I39d segue to the SQL Server Columnstore index, which offers a scenario to improve the performance of this query in amazing ways. But before I do that, let39s go back in time. Let39s go back to the year 2010, when Microsoft introduced an add-in for Excel known as PowerPivot. Many people probably remember seeing demos of PowerPivot for Excel, where a user could read millions of rows from an outside data source into Excel. PowerPivot would compress the data, and provide an engine to create Pivot Tables and Pivot Charts that performed at amazing speeds against the compressed data. PowerPivot used an in-memory technology that Microsoft termed quotVertiPaqquot. This in-memory technology in PowerPivot would basically take duplicate business keyforeign key values and compress them down to a single vector. The in-memory technology would also scanaggregate these values in parallel, in blocks of several hundred at a time. The bottom line is that Microsoft baked a large amount of performance enhancements into the VertiPaq in-memory feature for us to use, right out of the proverbial box. Why am I taking this little stroll down memory lane Because in SQL Server 2012, Microsoft implemented one of the most important features in the history of their database engine: the Columnstore index. The index is really an index in name only: it is a way to take a SQL Server table and create a compressed, in-memory columnstore that compresses duplicate foreign key values down to single vector values. Microsoft also created a new buffer pool to read these compressed vector values in parallel, creating the potential for huge performance gains. So, I39m going to create a columnstore index on the table, and I39ll see how much better (and more efficiently) the query runs, versus the query that runs against the covering index. So, I39ll create a duplicate copy of FactOnlineSales (I39ll call it FactOnlineSalesDetailNCCS), and I39ll create a columnstore index on the duplicated table that way I won39t interfere with the original table and the covering index in any way. Next, I39ll create a columnstore index on the new table: Note several things: I39ve specified several foreign key columns, as well as the Sales Amount. Remember that a columnstore index is not like a traditional row-store index. There is no quotkeyquot. We are simply indicating which columns SQL Server should compress and place in an in-memory columnstore. To use the analogy of PowerPivot for Excel when we create a columnstore index, we39re telling SQL Server to essentially do the same thing that PowerPivot did when we imported 20 million rows into Excel using PowerPivot So, I39ll re-run the query, this time using the duplicated FactOnlineSalesDetailNCCS table that contains the columnstore index. This query runs instantly in less than a second. And I can also say that even if the table had hundreds of millions of rows, it would still run at the proverbial quotbat of an eyelashquot. We could look at the execution plan (and in a few moments, we will), but now it39s time to cover the Query Store feature. Imagine for a moment, that we ran both queries overnight: the query that used the regular FactOnlineSales table (with the covering index) and then the query that used the duplicated table with the Columnstore index. When we log in the following morning, we39d like to see the execution plan for both queries as they took place, as well as the execution statistics. In other words, we39d like to see the same statistics that we39d be able to see if we ran both queries interactively in SQL Management Studio, turned in TIME and IO Statistics, and viewed the execution plan right after executing the query. Well, that39s what the Query Store allows us to do we can turn on (enable) Query Store for a database, which will trigger SQL Server to store query execution and plan statistics so that we can view them later. So, I39m going to enable the Query Store on the Contoso database with the following command (and I39ll also clear out any caching): Then I39ll run the two queries (and quotpretendquot that I ran them hours ago): Now let39s pretend they ran hours ago. According to what I said, the Query Store will capture the execution statistics. So how do I view them Fortunately, that39s quite easy. If I expand the Contoso DW database, I39ll see a Query Store folder. The Query Store has tremendous functionality and I39ll try to cover much of it in subsequent blog posts. But for right now, I want to view execution statistics on the two queries, and specifically examine the execution operators for the columnstore index. So I39ll right-click on the Top Resource Consuming Queries and run that option. That gives me a chart like the one below, where I can see execution duration time (in milliseconds) for all queries that have been executed. In this instance, Query 1 was the query against the original table with the covering index, and Query 2 was against the table with the columnstore index. The numbers don39t lie the columnstore index outperformed the original tablecovering index by a factor of almost 7 to 1. I can change the metric to look at memory consumption instead. In this case, note that query 2 (the columnstore index query) used far more memory. This demonstrates clearly why the columnstore index represents quotin-memoryquot technology SQL Server loads the entire columnstore index in memory, and uses a completely different buffer pool with enhanced execution operators to process the index. OK, so we have some graphs to view execution statistics can we see the execution plan (and execution operators) associated with each execution Yes, we can If you click on the vertical bar for the query that used the columnstore index, you39ll see the execution plan below. The first thing we see is that SQL Server performed a columnstore index scan, and that represented nearly 100 of the cost of the query. You might be saying, quotWait a minute, the first query used a covering index and performed an index seek so how can a columnstore index scan be fasterquot That39s a legitimate question, and fortunately there39s an answer. Even when the first query performed an index seek, it still executed quotrow by rowquot. If I put the mouse over the columnstore index scan operator, I see a tooltip (like the one below), with one important setting: the Execution Mode is BATCH (as opposed to ROW . which is what we had with the first query using the covering index). That BATCH mode tells us that SQL Server is processing the compressed vectors (for any foreign key values that are duplicated, such as the product key and date key) in batches of almost 1,000, in parallel. So SQL Server is still able to process the columnstore index much more efficiently. Additionally, if I place the mouse over the Hash Match (Aggregate) task, I also see that SQL Server is aggregating the columnstore index using Batch mode (although the operator itself represents such a tiny percent of the cost of the query) Finally, you might be asking, quotOK, so SQL Server compresses the values in the data, treats the values as vectors, and read them in blocks of almost a thousand values in parallel but my query only wanted data for 2009. So is SQL Server scanning over the entire set of dataquot Again, a good question. The answer is, quotNot reallyquot. Fortunately for us, the new columnstore index buffer pool performs another function called quotsegment eliminationquot. Basically, SQL Server will examine the vector values for the date key column in the columnstore index, and eliminate segments that are outside the scope of the year 2009. I39ll stop here. In subsequent blog posts I39ll cover both the columnstore index and Query Store in more detail. Essentially, what we39ve seen here today is that the Columnstore index can significantly speed up queries that scanaggregate over large amounts of data, and the Query Store will capture query executions and allow us to examine execution and performance statistics later. In the end, we39d like to produce a result set that shows the following. Notice three things: The columns essentially pivot all of the possible Return Reasons, after showing the sales amount The result set contains subtotals by the week ending (Sunday) date across all clients (where the Client is NULL) The result set contains a grand total row (where the Client and Date are both NULL) First, before I get into the SQL end we could use the dynamic pivotmatrix capability in SSRS. We would simply need to combine the two result sets by one column and then we could feed the results to the SSRS matrix control, which will spread the return reasons across the columns axis of the report. However, not everyone uses SSRS (though most people should). But even then, sometimes developers need to consume result sets in something other than a reporting tool. So for this example, let39s assume we want to generate the result set for a web grid page and possibly the developer wants to quotstrip outquot the subtotal rows (where I have a ResultSetNum value of 2 and 3) and place them in a summary grid. So bottom line, we need to generate the output above directly from a stored procedure. And as an added twist next week there could be Return Reason X and Y and Z. So we don39t know how many return reasons there could be. We simple want the query to pivot on the possible distinct values for Return Reason. Here is where the T-SQL PIVOT has a restriction we need to provide it the possible values. Since we won39t know that until run-time, we need to generate the query string dynamically using the dynamic SQL pattern. The dynamic SQL pattern involves generating the syntax, piece by piece, storing it in a string, and then executing the string at the end. Dynamic SQL can be tricky, as we have to embed syntax inside a string. But in this case, it our only true option if we want to handle a variable number of return reasons. I39ve always found that the best way to create a dynamic SQL solution is by figuring out what the quotidealquot generated-query would be at the end (in this case, given the Return reasons we know about).and then reverse-engineering it by piecing it together one part at a time. And so, here is the SQL we need if we knew those Return Reasons (A through D) were static and would not change. The query does the following: Combines the data from SalesData with the data from ReturnData, where we quothard-wirequot the word Sales as an Action Type form the Sales Table, and then use the Return Reason from the Return Data into the same ActionType column. That will give us a clean ActionType column on which to pivot. We are combining the two SELECT statements into a common table expression (CTE), which is basically a derived table subquery that we subsequently use in the next statement (to PIVOT) A PIVOT statement against the CTE, that sums the dollars for the Action Type being in one of the possible Action Type values. Note that this isn39t the final result set. We are placing this into a CTE that reads from the first CTE. The reason for this is because we want to do multiple groupings at the end. The final SELECT statement, that reads from the PIVOTCTE, and combines it with a subsequent query against the same PIVOTCTE, but where we also implement two groupings in the GROUPING SETS feature in SQL 2008: GROUPING by the Week End Date (dbo. WeekEndingDate) GROUPING for all rows () So if we knew with certainty that we39d never have more return reason codes, then that would be the solution. However, we need to account for other reason codes. So we need to generate that entire query above as one big string where we construct the possible return reasons as one comma separated list. I39m going to show the entire T-SQL code to generate (and execute) the desired query. And then I39ll break it out into parts and explain each step. So first, here39s the entire code to dynamically generate what I39ve got above. There are basically five steps we need to cover. الخطوة 1 . we know that somewhere in the mix, we need to generate a string for this in the query: SalesAmount, Reason A, Reason B, Reason C, Reason D0160016001600160 What we can do is built a temporary common table expression that combines the hard wired quotSales Amountquot column with the unique list of possible reason codes. Once we have that in a CTE, we can use the nice little trick of FOR XML PATH(3939) to collapse those rows into a single string, put a comma in front of each row that the query reads, and then use STUFF to replace the first instance of a comma with an empty space. This is a trick that you can find in hundreds of SQL blogs. So this first part builds a string called ActionString that we can use further down. الخطوة 2 . we also know that we39ll want to SUM the generatedpivoted reason columns, along with the standard sales column. So we39ll need a separate string for that, which I39ll call SUMSTRING. I39ll simply use the original ActionString, and then REPLACE the outer brackets with SUM syntax, plus the original brackets. Step 3: Now the real work begins. Using that original query as a model, we want to generate the original query (starting with the UNION of the two tables), but replacing any references to pivoted columns with the strings we dynamically generated above. Also, while not absolutely required, I39ve also created a variable to simply any carriage returnline feed combinations that we want to embed into the generated query (for readability). So we39ll construct the entire query into a variable called SQLPivotQuery. Step 4 . We continue constructing the query again, concatenating the syntax we can quothard-wirequot with the ActionSelectString (that we generated dynamically to hold all the possible return reason values) Step 5 . Finally, we39ll generate the final part of the Pivot Query, that reads from the 2 nd common table expression (PIVOTCTE, from the model above) and generates the final SELECT to read from the PIVOTCTE and combine it with a 2 nd read against PIVOTCTE to implement the grouping sets. Finally, we can quotexecutequot the string using the SQL system stored proc spexecuteSQL So hopefully you can see that the process to following for this type of effort is Determine what the final query would be, based on your current set of data and values (i. e. built a query model) Write the necessary T-SQL code to generate that query model as a string. Arguably the most important part is determining the unique set of values on which you39ll PIVOT, and then collapsing them into one string using the STUFF function and the FOR XML PATH(3939) trick So whats on my mind today Well, at least 13 items Two summers ago, I wrote a draft BDR that focused (in part) on the role of education and the value of a good liberal arts background not just for the software industry but even for other industries as well. One of the themes of this particular BDR emphasized a pivotal and enlightened viewpoint from renowned software architect Allen Holub regarding liberal arts. Ill (faithfully) paraphrase his message: he highlighted the parallels between programming and studying history, by reminding everyone that history is reading and writing (and Ill add, identifying patterns), and software development is also reading and writing (and again, identifying patterns). And so I wrote an opinion piece that focused on this and other related topics. But until today, I never got around to either publishingposting it. Every so often Id think of revising it, and Id even sit down for a few minutes and make some adjustments to it. But then life in general would get in the way and Id never finish it. So what changed A few weeks ago, fellow CoDe Magazine columnist and industry leader Ted Neward wrote a piece in his regular column, Managed Coder , that caught my attention. The title of the article is On Liberal Arts. and I highly recommend that everyone read it. Ted discusses the value of a liberal arts background, the false dichotomy between a liberal arts background and success in software development, and the need to writecommunicate well. He talks about some of his own past encounters with HR personnel management regarding his educational background. He also emphasizes the need to accept and adapt to changes in our industry, as well as the hallmarks of a successful software professional (being reliable, planning ahead, and learning to get past initial conflict with other team members). So its a great read, as are Teds other CoDe articles and blog entries. It also got me back to thinking about my views on this (and other topics) as well, and finally motivated me to finish my own editorial. So, better late than never, here are my current Bakers Dozen of Reflections: I have a saying: Water freezes at 32 degrees . If youre in a trainingmentoring role, you might think youre doing everything in the world to help someone when in fact, theyre only feeling a temperature of 34 degrees and therefore things arent solidifying for them. Sometimes it takes just a little bit more effort or another ideachemical catalyst or a new perspective which means those with prior education can draw on different sources. Water freezes at 32 degrees . Some people can maintain high levels of concentration even with a room full of noisy people. Im not one of them occasionally I need some privacy to think through a critical issue. Some people describe this as you gotta learn to walk away from it. Stated another way, its a search for the rarefied air. This past week I spent hours in half-lit, quiet room with a whiteboard, until I fully understood a problem. It was only then that I could go talk with other developers about a solution. The message here isnt to preach how you should go about your business of solving problems but rather for everyone to know their strengths and what works, and use them to your advantage as much as possible. Some phrases are like fingernails on a chalkboard for me. Use it as a teaching moment is one. (Why is it like fingernails on a chalkboard Because if youre in a mentoring role, you should usually be in teaching moment mode anyway, however subtly). Heres another I cant really explain it in words, but I understand it. This might sound a bit cold, but if a person truly cant explain something in words, maybe they dont understand. Sure, a person can have a fuzzy sense of how something works I can bluff my way through describing how a digital camera works but the truth is that I dont really understand it all that well. There is a field of study known as epistemology (the study of knowledge). One of the fundamental bases of understanding whether its a camera or a design pattern - is the ability to establish context, to identify the chain of related events, the attributes of any components along the way, etc. Yes, understanding is sometimes very hard work, but diving into a topic and breaking it apart is worth the effort. Even those who eschew certification will acknowledge that the process of studying for certification tests will help to fill gaps in knowledge. A database manager is more likely to hire a database developer who can speak extemporaneously (and effortlessly) about transaction isolation levels and triggers, as opposed to someone who sort of knows about it but struggles to describe their usage. Theres another corollary here. Ted Neward recommends that developers take up public speaking, blogging, etc. I agree 100. The process of public speaking and blogging will practically force you to start thinking about topics and breaking down definitions that you might have otherwise taken for granted. A few years ago I thought I understood the T-SQL MERGE statement pretty well. But only after writing about it, speaking about, fielding questions from others who had perspectives that never occurred to me that my level of understanding increased exponentially. I know a story of a hiring manager who once interviewed an authordeveloper for a contract position. The hiring manager was contemptuous of publications in general, and barked at the applicant, So, if youre going to work here, would you rather be writing books or writing code Yes, Ill grant that in any industry there will be a few pure academics. But what the hiring manager missed was the opportunities for strengthening and sharpening skill sets. While cleaning out an old box of books, I came across a treasure from the 1980s: Programmers at Work. which contains interviews with a very young Bill Gates, Ray Ozzie, and other well-known names. Every interview and every insight is worth the price of the book. In my view, the most interesting interview was with Butler Lampson. who gave some powerful advice. To hell with computer literacy. Its absolutely ridiculous. Study mathematics. Learn to think. اقرأ. Write. These things are of more enduring value. Learn how to prove theorems: A lot of evidence has accumulated over the centuries that suggests this skill is transferable to many other things. Butler speaks the truth . Ill add to that point learn how to play devils advocate against yourself. The more you can reality-check your own processes and work, the better off youll be. The great computer scientistauthor Allen Holub made the connection between software development and the liberal arts specifically, the subject of history. Here was his point: what is history Reading and writing. What is software development Among other things, reading and writing . I used to give my students T-SQL essay questions as practice tests. One student joked that I acted more like a law professor. Well, just like Coach Donny Haskins said in the movie Glory Road, my way is hard. I firmly believe in a strong intellectual foundation for any profession. Just like applications can benefit from frameworks, individuals and their thought processes can benefit from human frameworks as well. Thats the fundamental basis of scholarship. There is a story that back in the 1970s, IBM expanded their recruiting efforts in the major universities by focusing on the best and brightest of liberal arts graduates. Even then they recognized that the best readers and writers might someday become strong programmersystems analysts. (Feel free to use that story to any HR-type who insists that a candidate must have a computer science degree) And speaking of history: if for no other reason, its important to remember the history of product releases if Im doing work at a client site thats still using SQL Server 2008 or even (gasp) SQL Server 2005, I have to remember what features were implemented in the versions over time. Ever have a favorite doctor whom you liked because heshe explained things in plain English, gave you the straight truth, and earned your trust to operate on you Those are mad skills . and are the result of experience and HARD WORK that take years and even decades to cultivate. There are no guarantees of job success focus on the facts, take a few calculated risks when youre sure you can see your way to the finish line, let the chips fall where they may, and never lose sight of being just like that doctor who earned your trust. Even though some days I fall short, I try to treat my client and their data as a doctor would treat patients. Even though a doctor makes more money There are many clichs I detest but heres one I dont hate: There is no such thing as a bad question. As a former instructor, one thing that drew my ire was hearing someone criticize another person for asking a supposedly, stupid question. A question indicates a person acknowledges they have some gap in knowledge theyre looking to fill. Yes, some questions are better worded than others, and some questions require additional framing before they can be answered. But the journey from forming a question to an answer is likely to generate an active mental process in others. There are all GOOD things. Many good and fruitful discussions originate with a stupid question. I work across the board in SSIS, SSAS, SSRS, MDX, PPS, SharePoint, Power BI, DAX all the tools in the Microsoft BI stack. I still write some code from time to time. But guess what I still spend so much time doing writing T-SQL code to profile data as part of the discovery process. All application developers should have good T-SQL chops. Ted Neward writes (correctly) about the need to adapt to technology changes. Ill add to that the need to adapt to clientemployer changes. Companies change business rules. Companies acquire other companies (or become the target of an acquisition). Companies make mistakes in communicating business requirements and specifications. Yes, we can sometimes play a role in helping to manage those changes and sometimes were the fly, not the windshield. These sometimes cause great pain for everyone, especially the I. T. people. This is why the term fact of life exists we have to deal with it. Just like no developer writes bug-free code every time, no I. T. person deals well with change every single time. One of the biggest struggles Ive had in my 28 years in this industry is showing patience and restraint when changes are flying from many different directions. Here is where my prior suggestion about searching for the rarified air can help. If you can manage to assimilate changes into your thought process, and without feeling overwhelmed, odds are youll be a significant asset. In the last 15 months Ive had to deal with a huge amount of professional change. Its been very difficult at times, but Ive resolved that change will be the norm and Ive tried to tweak my own habits as best I can to cope with frequent (and uncertain) change. Its hard, very hard. But as coach Jimmy Duggan said in the movie A League of Their Own: Of course its hard. If it wasnt hard, everyone would do it. The hard, is what makes it great . A powerful message. Theres been talk in the industry over the last few years about conduct at professional conferences (and conduct in the industry as a whole). Many respected writers have written very good editorials on the topic. Heres my input, for what its worth. Its a message to those individuals who have chosen to behave badly: Dude, it shouldnt be that hard to behave like an adult. A few years ago, CoDe Magazine Chief Editor Rod Paddock made some great points in an editorial about Codes of Conduct at conferences. Its definitely unfortunate to have to remind people of what they should expect out of themselves. But the problems go deeper. A few years ago I sat on a five-person panel (3 women, 2 men) at a community event on Women in Technology. The other male stated that men succeed in this industry because the Y chromosome gives men an advantage in areas of performance. The individual who made these remarks is a highly respected technology expert, and not some bozo making dongle remarks at a conference or sponsoring a programming contest where first prize is a date with a bikini model. Our world is becoming increasingly polarized (just watch the news for five minutes), sadly with emotion often winning over reason. Even in our industry, recently I heard someone in a position of responsibility bash software tool XYZ based on a ridiculous premise and then give false praise to a competing tool. So many opinions, so many arguments, but heres the key: before taking a stand, do your homework and get the facts . Sometimes both sides are partly rightor wrong. Theres only one way to determine: get the facts. As Robert Heinlein wrote, Facts are your single clue get the facts Of course, once you get the facts, the next step is to express them in a meaningful and even compelling way. Theres nothing wrong with using some emotion in an intellectual debate but it IS wrong to replace an intellectual debate with emotion and false agenda. A while back I faced resistance to SQL Server Analysis Services from someone who claimed the tool couldnt do feature XYZ. The specifics of XYZ dont matter here. I spent about two hours that evening working up a demo to cogently demonstrate the original claim was false. In that example, it worked. I cant swear it will always work, but to me thats the only way. Im old enough to remember life at a teen in the 1970s. Back then, when a person lost hisher job, (often) it was because the person just wasnt cutting the mustard. Fast-forward to today: a sad fact of life is that even talented people are now losing their jobs because of the changing economic conditions. Theres never a full-proof method for immunity, but now more than ever its critical to provide a high level of what I call the Three Vs (value, versatility, and velocity) for your employerclients. I might not always like working weekends or very late at night to do the proverbial work of two people but then I remember there are folks out there who would give anything to be working at 1 AM at night to feed their families and pay their bills. Always be yourselfyour BEST self. Some people need inspiration from time to time. Heres mine: the great sports movie, Glory Road. If youve never watched it, and even if youre not a sports fan I can almost guarantee youll be moved like never before. And Ill close with this. If you need some major motivation, Ill refer to a story from 2006. Jason McElwain, a high school student with autism, came off the bench to score twenty points in a high school basketball game in Rochester New York. Heres a great YouTube video. His mother said it all . This is the first moment Jason has ever succeeded and is proud of himself. I look at autism as the Berlin Wall. He cracked it. To anyone who wanted to attend my session at todays SQL Saturday event in DC I apologize that the session had to be cancelled. I hate to make excuses, but a combination of getting back late from Detroit (client trip), a car thats dead (blown head gasket), and some sudden health issues with my wife have made it impossible for me to attend. Back in August, I did the same session (ColumnStore Index) for PASS as a webinar. You can go to this link to access the video (itll be streamed, as all PASS videos are streamed) The link does require that you fill out your name and email address, but thats it. And then you can watch the video. Feel free to contact me if you have questions, at kgoffkevinsgoff November 15, 2013 Getting started with Windows Azure and creating SQL Databases in the cloud can be a bit daunting, especially if youve never tried out any of Microsofts cloud offerings. Fortunately, Ive created a webcast to help people get started. This is an absolute beginners guide to creating SQL Databases under Windows Azure. It assumes zero prior knowledge of Azure. You can go to the BDBI Webcasts of this website and check out my webcast (dated 11102013). Or you can just download the webcast videos right here: here is part 1 and here is part 2. You can also download the slide deck here. November 03, 2013 Topic this week: SQL Server Snapshot Isolation Levels, added in SQL Server 2005. To this day, there are still many SQL developers, many good SQL developers who either arent aware of this feature, or havent had time to look at it. Hopefully this information will help. Companion webcast will be uploaded in the next day look for it in the BDBI Webcasts section of this blog. October 26, 2013 Im going to start a weekly post of T-SQL tips, covering many different versions of SQL Server over the years Heres a challenge many developers face. Ill whittle it down to a very simple example, but one where the pattern applies to many situations. Suppose you have a stored procedure that receives a single vendor ID and updates the freight for all orders with that vendor id. create procedure dbo. UpdateVendorOrders update Purchasing. PurchaseOrderHeader set Freight Freight 1 where VendorID VendorID Now, suppose we need to run this for a set of vendor IDs. Today we might run it for three vendors, tomorrow for five vendors, the next day for 100 vendors. We want to pass in the vendor IDs. If youve worked with SQL Server, you can probably guess where Im going with this. The big question is how do we pass a variable number of Vendor IDs Or, stated more generally, how do we pass an array, or a table of keys, to a procedure Something along the lines of exec dbo. UpdateVendorOrders SomeListOfVendors Over the years, developers have come up with different methods: Going all the way back to SQL Server 2000, developers might create a comma-separated list of vendor keys, and pass the CSV list as a varchar to the procedure. The procedure would shred the CSV varchar variable into a table variable and then join the PurchaseOrderHeader table to that table variable (to update the Freight for just those vendors in the table). I wrote about this in CoDe Magazine back in early 2005 (code-magazinearticleprint. aspxquickid0503071ampprintmodetrue. Tip 3) In SQL Server 2005, you could actually create an XML string of the vendor IDs, pass the XML string to the procedure, and then use XQUERY to shred the XML as a table variable. I also wrote about this in CoDe Magazine back in 2007 (code-magazinearticleprint. aspxquickid0703041ampprintmodetrue. Tip 12)Also, some developers will populate a temp table ahead of time, and then reference the temp table inside the procedure. All of these certainly work, and developers have had to use these techniques before because for years there was NO WAY to directly pass a table to a SQL Server stored procedure. Until SQL Server 2008 when Microsoft implemented the table type. This FINALLY allowed developers to pass an actual table of rows to a stored procedure. Now, it does require a few steps. We cant just pass any old table to a procedure. It has to be a pre-defined type (a template). So lets suppose we always want to pass a set of integer keys to different procedures. One day it might be a list of vendor keys. Next day it might be a list of customer keys. So we can create a generic table type of keys, one that can be instantiated for customer keys, vendor keys, etc. CREATE TYPE IntKeysTT AS TABLE ( IntKey int NOT NULL ) So Ive created a Table Typecalled IntKeysTT . Its defined to have one column an IntKey. Nowsuppose I want to load it with Vendors who have a Credit Rating of 1..and then take that list of Vendor keys and pass it to a procedure: DECLARE VendorList IntKeysTT INSERT INTO VendorList SELECT BusinessEntityID from Purchasing. Vendor WHERE CreditRating 1 So, I now have a table type variable not just any table variable, but a table type variable (that I populated the same way I would populate a normal table variable). Its in server memory (unless it needs to spill to tempDB) and is therefore private to the connectionprocess. OK, can I pass it to the stored procedure now Well, not yet we need to modify the procedure to receive a table type. Heres the code: create procedure dbo. UpdateVendorOrdersFromTT IntKeysTT IntKeysTT READONLY update Purchasing. PurchaseOrderHeader set Freight Freight 1 FROM Purchasing. PurchaseOrderHeader JOIN IntKeysTT TempVendorList ON PurchaseOrderHeader. VendorID Te mpVendorList. IntKey Notice how the procedure receives the IntKeysTT table type as a Table Type (again, not just a regular table, but a table type). It also receives it as a READONLY parameter. You CANNOT modify the contents of this table type inside the procedure. Usually you wont want to you simply want to read from it. Well, now you can reference the table type as a parameter and then utilize it in the JOIN statement, as you would any other table variable. لذلك هناك لديك. A bit of work to set up the table type, but in my view, definitely worth it. Additionally, if you pass values from , youre in luck. You can pass an ADO data table (with the same tablename property as the name of the Table Type) to the procedure. For developers who have had to pass CSV lists, XML strings, etc. to a procedure in the past, this is a huge benefit. Finally I want to talk about another approach people have used over the years. SQL Server Cursors. At the risk of sounding dogmatic, I strongly advise against Cursors, unless there is just no other way. Cursors are expensive operations in the server, For instance, someone might use a cursor approach and implement the solution this way: DECLARE VendorID int DECLARE dbcursor CURSOR FASTFORWARD FOR SELECT BusinessEntityID from Purchasing. Vendor where CreditRating 1 FETCH NEXT FROM dbcursor INTO VendorID WHILE FETCHSTATUS 0 EXEC dbo. UpdateVendorOrders VendorID FETCH NEXT FROM dbcursor INTO VendorID The best thing Ill say about this is that it works. And yes, getting something to work is a milestone. But getting something to work and getting something to work acceptably are two different things. Even if this process only takes 5-10 seconds to run, in those 5-10 seconds the cursor utilizes SQL Server resources quite heavily. Thats not a good idea in a large production environment. Additionally, the more the of rows in the cursor to fetch and the more the number of executions of the procedure, the slower it will be. When I ran both processes (the cursor approach and then the table type approach) against a small sampling of vendors (5 vendors), the processing times where 260 ms and 60 ms, respectively. So the table type approach was roughly 4 times faster. But then when I ran the 2 scenarios against a much larger of vendors (84 vendors), the different was staggering 6701 ms versus 207 ms, respectively. So the table type approach was roughly 32 times faster. Again, the CURSOR approach is definitely the least attractive approach. Even in SQL Server 2005, it would have been better to create a CSV list or an XML string (providing the number of keys could be stored in a scalar variable). But now that there is a Table Type feature in SQL Server 2008, you can achieve the objective with a feature thats more closely modeled to the way developers are thinking specifically, how do we pass a table to a procedure Now we have an answer Hope you find this feature help. Feel free to post a comment.

No comments:

Post a Comment