You are on page 1of 6

‫‪Scaling ADO.

NET DataTables‬‬

‫قياس اداء جداول ‪ADO .net‬‬

‫تتوفر عدة استراتٌجٌات لتطوٌر قواعد البٌانات فً بٌئة تطوٌر الدوت نٌت فرٌموورك مثل ‪ADO.NET Entity‬‬
‫‪ Framework‬و ‪ ASP.NET Dynamic Data‬و ‪ XML‬و ‪ Hibernate‬و ‪ Linq to Sql‬و ‪ObjectDataSource‬‬
‫وغٌرها ومع ذلك ستجد فً كثٌر من الحاالت أن جداول ‪ ado .net‬ما زالت قٌد االستخدام ربما ٌكون هذا بسبب أن‬
‫المعمارٌة الحالٌة تعتمد على جداول البٌانات أو لسهولة استخدامها فربما ٌتطلب العمل البقاء على الدوت نٌت ‪ 1‬وربما لم‬
‫ٌتوفر لدٌك الوقت لتصفح الطرق األخرى للوصول إلى البٌانات ومهما كان السبب فمن المفٌد أن نتعلم كٌفٌة زٌادة اداء‬
‫جدول البٌانات للحد األقصى وسوف نبحث فً اثنٌن من السٌنارٌوهات الشائعة ‪ :‬االستعالم عن البٌانات وتجمٌع البٌانات‬

‫االستعالم عن البيانات‬
‫قبل أن نناقش كٌفٌة التعامل مع البٌانات فً الذاكرة والمعاٌٌر المرتبطة بها دعنً أوضح انه فً معظم الحاالت ٌبدو‬
‫منطقٌا تجمٌع البٌانات أو االستعالم عنها فً قاعدة البٌانات‪ .‬وهناك عدة أسباب لهذا فالسبب األول هو كون محرك قاعدة‬
‫البٌانات معاٌر بشكل جٌد من أجل القٌام بهذه العملٌات وسنرى بعد قلٌل أن جداول بٌانات ‪ ado .net‬لٌست بهذه الكفاءة‬
‫والسبب الثانً هو أنك كلما نقلت كمٌة بٌانات أقل عبر السلك ستحصل على أداء أفضل لعملٌات قواعد البٌانات وهذا ٌعنً‬
‫انك بحاجة لنقل النتائج فقط ولٌس البٌانات الخام والثالث إذا كنت تقوم بخزن كمٌات كبٌرة من البٌانات على اآللة المحلٌة‬
‫فسوف تواجه خطر عرض بٌانات قدٌمة للمستخدمٌن مما قد ٌجعلك عرضة ألن ٌتعامل مستخدمو تطبٌقك مع عدة نسخ‬
‫غٌر متزامنة من البٌانات‬

‫ومع أخذ هذا التحذٌر بعٌن االعتبار دعنا نتحدث عن سٌنارٌو ٌكون معقوال من أجل كمٌات كبٌرة من البٌانات ٌتم تخزٌنها‬
‫محلٌا‪ .‬قد ٌكون لدٌك عدد من الجداول الثابتة تكون موجودة فقط من أجل توفٌر بٌانات تطبٌع وغالبا ما تعرف بجداول‬
‫البحث وأنا اتعامل ٌومٌا مع العدٌد من جداول البحث التً تحتوي على مجموعات مختلفة من البٌانات محددة بالسنة بما ان‬
‫المستخدمٌن ٌمكن ان ٌتعاملوا مع بٌانات من السنوات السابقة ربما نحتاج إلى تقدٌم بٌانات بحث من اٌة سنة فً أي وقت‬
‫وٌتشعب هذا السٌنارٌو فً حالة الزبائن الذٌن ٌتعاملون منذ فترة طوٌلة فهؤالء ٌكون لهم بٌانات بحث أكثر من الزبائن‬
‫الجدد وقد تصبح األمور أسوأ بسبب طبٌعة البٌانات فالزبائن األكبر ٌمٌلون ألن ٌكون لهم إدخاالت أكثر فً جداول البحث‬
‫لكل عام وهذا سٌؤدي إلى بعض المشاكل المتعلقة باألداء بما ان جداول بٌانات ‪ ADO .net‬ال تتدرج جٌدا من ناحٌة‬
‫السرعة عندما ٌتم التعامل معها بسذاجة ففً بٌئة التطوٌر ٌكون لدٌنا لكل جدول بحث عدد قلٌل من السجالت وفً‬
‫االختبار العملً قد ٌكون هناك أكثر من ‪ 09999‬سجل فً الجدول الواحد وبهذا ٌنخفض األداء بصورة ملحوظة مع‬
‫مجموعات البٌانات األكبر‬

‫لماذا تكون هناك مشاكل فً األداء؟ أحد‬


‫األسباب هو االستخدام المتكرر لجدول‬
‫البٌانات فاالستعالم ٌأخذ معاٌٌر عشوائٌة‬
‫وٌعٌد مصفوفة من سطور البٌانات‬
‫وباألساس ٌجب على االستعالم المرور‬
‫عبر كامل الجدول لمقارنة كل سجل مع‬
‫المعاٌٌر الممررة‪.‬‬

‫فالدالة‬ ‫أخرى‬ ‫ناحٌة‬ ‫ومن‬


‫‪ DataTable.Rows.Find‬تعٌد سجال‬
‫وحٌدا فقط وأساسا عندما تحدد مفتاحا‬
‫اساسٌا ٌتم إنشاء شجرة ثنائٌة وهذا ٌتطلب بعض النفقات المرتبطة به ولكنه ٌؤدي إلى تسرٌع االستعادة عند االستعالم‬

‫وكم سٌتطلب ذلك؟ هذا ٌعتمد على بعض العوامل األول هو عدد السطور فً السجل والثانً هو هل قمت بإنشاء فهرس‬
‫‪ Index‬قبل أو بعد ان تضٌف البٌانات حٌث ٌظهر الشكل أزمان كبٌرة مرتبطة بإنشاء الفهرس قبل إضافة البٌانات‬
‫وبتفحص البٌانات ستجد فرق بٌن ‪ %09‬إلى ‪ %09‬فً الوقت المأخوذ إلنشاء وفهرسة الجداول‬

‫ٌمكنك تنفٌذ نفس مقٌاس السرعة باستخدام زر ‪ Index Creation‬فً واجهة قٌاس السرعة ‪Benchmarking UI‬‬
‫والكود المصدري المستخدم فً هذا المقٌاس موجود فً ‪ MSDN Code Gallery‬ومن الشكل فً األعلى ٌمكنك رؤٌة‬
‫أنه سٌأخذ خمس ثوانً لفهرسة جدول ٌحتوي على ‪ 199999‬سجل‪ .‬ولفهرسة جدول بٌانات سوف تحتاج لتوفٌر مصفوفة‬
‫من أعمدة البٌانات من مفتاح فرٌد للسجالت فً جدول البٌانات مثال‪:‬‬

‫})"‪dtIndexed.PrimaryKey = New DataColumn() {dtIndexed.Columns("Key‬‬

‫مع معرفة ان هناك تعقٌدات تتعلق باألداء إلنشاء هذه الفهارس أنصح بنقل عملٌة الفهرسة إلى الخلفٌة وعمل ذلك بشكل ال‬
‫متزامن‪ .‬مع مالحظة أن جداول البٌانات ال تكون آمنة وراثٌا عبر المسارات ‪ Not Thread safe‬لذا علٌك ان تكون‬
‫حذرا أثناء القٌام بهذا وٌعتبر العنصر ‪ BackgroundWorker‬خٌارا جمٌال لهذا الهدف بما أن جدول البٌانات لن ٌكون‬
‫متوفرا للمسار الرئٌسً لغاٌة اكتمال عملٌة إنشاء الجدول وفهرسته ونشره‪ .‬وسٌصبح السؤال هل تستحق المنفعة المكتسبة‬
‫هذه الخمس ثوانً تأخٌر؟ دعنا نرى الفرق فً األداء بٌن عدة طرق لالستعالم من جدول بٌانات‬

‫أداء استجابة البيانات‬


‫قبل أن أناقش اختبار األداء دعنً اتكلم عن كٌفٌة ضبط اختبارات األداء بحٌث ٌبٌن لنا التالً قطعة كود قٌاسٌة‬
‫)(‪Private Sub RunIndexCreationTest‬‬
‫‪' make sure all libraries are loaded‬‬
‫)‪TestIndexCreation(1‬‬
‫)‪Dim results As New List(Of IndexCreationResult‬‬
‫‪For Each arraySize As Integer In arraySizes‬‬
‫))‪results.Add(TestIndexCreation(arraySize‬‬
‫‪Next‬‬
‫)‪CsvFileOutput(Of IndexCreationResult).Output("filename”, results‬‬

‫‪End Sub‬‬

‫أول شئ نفعله فً جمٌع اختبارات االداء هو استدعاء االختبار وتنفٌذه على جدول البٌانات من أجل عنصر وحٌد هذه‬
‫العملٌة تجبر المكتبات المطلوبة على التحمٌل وتجنبنا الحصول على زمن تنفٌذ عالً أثناء االختبار األول بحٌث ٌمكننا‬
‫بعدها تنفٌذ االختبار من اجل جداول تحتوي على ‪ 19‬إلى ‪ 1999999‬سجل فً كل اختبار اداء وٌتم اعادة العملٌة عدة‬
‫مرات وٌؤخذ متوسط النتائج مما ٌخفف أٌة نتائج متأثرة بظروف غٌر متوقعة ثم ٌتم حفظ النتائج فً مل ‪ CSV‬فً المجلد‬
‫‪Bin\Debug‬‬

‫ٌحتوي اختبار استعالمات لٌنك ‪ Linq‬على سطر كود اضافً من اجل فرض تنفٌذ االستعالم فبما أن لٌنك تستخدم‬
‫استعالما مؤجال فستبدو ستبدو استعالمات لٌنك بدون هذا السطر وكأنها فورٌة بدون ان تعٌد النتٌجة فً الحقٌقة وقد قمت‬
‫بتنفٌذ استعالم لٌنك من أجل جداول مفهرسة وغٌر مفهرسة وهذا مثال ٌوضح انشاء استعالم لٌنك على داتاسٌت‬
‫‪Private Function TestLinqSearch(ByVal dt As DataTable, ByVal key As String) As Integer‬‬
‫‪Dim sw As New Stopwatch‬‬
‫)(‪sw.Start‬‬
‫)‪Dim result = From r In dt Where r(0) = key Select r(1‬‬
‫‪Dim output As String = result(0).ToString‬‬
‫)(‪sw.Stop‬‬
‫)‪Console.WriteLine(output‬‬
‫‪Return sw.ElapsedTicks‬‬

‫‪End Function‬‬
‫ٌبدا السطر فً األعلى بـ ‪ Dim Result‬إلنشاء استعالم لٌنك ومع ذلك فبسبب االستعالم المتأخر ال ٌتم تقٌٌمه حتى السطر‬
‫الذي ٌبدأ بـ ‪ Dim output‬وهذا االستدعاء الثانً مطلوب من اجل الحصول على صورة دقٌقة لألداء‪.‬‬

‫كلما كان ممكنا أزلت األعمال الزائدة مثل دمج النصوص والحصول على مرجع للعمود عندما ٌتم االشارة الٌه بواسطة‬
‫االسم من كود قٌاس االداء وهذا بالطبع ال ٌعكس حقٌقة الطرٌقة التً تستخدم فٌها جداول البٌانات فً العالم الحقٌقً وقد‬
‫تعمدت ذلك من أجل الحصول على افضل اداء ممكن من جدول البٌانات‬

‫واخٌرا جمٌع نتائج االختبارات هً بالتٌك ‪ tick‬ولٌس بالمٌللً ثانٌة والسبب فً ذلك بسٌط وهو أن نتائج البحث فً‬
‫الجداول المفهرسة والقوامٌس تكون سرٌعة جدا بحٌث ال ٌمكن قٌاسها بمجال المٌللً ثانٌة‪ .‬الحظ أٌضا ان فهرسة الجدول‬
‫تقدم أفضلٌة ضئٌلة الستعالم لٌنك وتأثٌر فهرسة الجدول عند التصفٌة بعدة أعمدة ٌتطلب استكشافا أكثر‬

‫ثالثا نظرا لسٌنارٌو الحصول على سجل واحد فقط من المجموعة تصبح عملٌة تحوٌل جدول بٌاناتك إلى قاموس هو البدٌل‬
‫األسرع واألكثر قابلٌة للقٌاس وفً سٌنارٌو أنه ٌوجد أكثر من سجل ستتم استعادته ٌجب أخذ لٌنك بجدٌة ونرى بوضوح‬
‫أن ماٌكروسوفت قد قامت بالعمل الكثٌر من أجل ضبط أداء لٌنك حتى من أجل مجموعات بٌانات كبٌرة وبما ان أي خٌار‬
‫غٌر ‪ DataTable.Select‬سٌتعامل بشكل جٌد مع مجموعات البٌانات الكبٌرة قم بتنظٌف كودك األساسً من‬
‫‪DataTable.Select‬‬

‫حول نتائج االختبار سترى أن األعمدة مرتبة بحسب المدة التً تستغرقها كل عملٌة بما أننً أقترح القاموس ‪dictionary‬‬
‫كبدٌل عن جدول البٌانات ‪ DataTable‬وقد ضمنت أٌضا تكلفة إنشاء قاموس )‪ Dictionary(Of String, String‬لٌضم‬
‫نفس البٌانات التً ٌتضمنها جدول البٌانات ستالحظ أن إنشاء قاموس أقل تكلفة من تنفٌذ ‪ DataTable.Select‬وحٌدة من‬
‫أجل البٌانات وطالما أنك تستعلم من البٌانات أكثر من مرة ٌثبت أن إنشاء قاموس هً العملٌة الرابحة وتجدر المالحظة أن‬
‫هناك بعض االختالفات فً القاموس بناء على نوع المفتاح‪ .‬ومع ذلك فإن استخدمت قاموسا او جدوال مفهرسا ستكلفك‬
‫عملٌة إعادة هٌكلة البٌانات إلى هٌكل أكثر كفاءة نفقات كثٌرة وهنا ٌبرز لٌنك كخٌار أفضل من منظور األداء إضافة إلى‬
‫أن الكود سٌصبح أسهل وأصغر وأكثر قابلٌة للقراءة من قبل أي شخص معتاد على عملٌات قواعد البٌانات‬
‫التجميع‬
‫حتى اآلن تكون النتٌجة ‪ 1‬الستعالمات لٌنك و ‪ 9‬لطرائق جدول البٌانات سنرى فً القسم الثانً إن كانت ‪ADO .net‬‬
‫‪ DataTable‬تستطٌع تخلٌص نفسها والبقاء ضمن المنافسة فً التجمٌع‪ .‬سوف نستخدم هنا نفس جدول البٌانات األساسً‬
‫الذي استخدمناه حتى اآلن ( جدول بٌانات غٌر مفهرس مع عمودٌن وعدد ‪ n‬من السجالت ) بحٌث ننفذ هنا ثالث عملٌات‬
‫تجمٌع أساسٌة ‪ Min‬و ‪ Max‬و ‪ AVG‬بحٌث ستبدو كالتالً‬
‫‪Dim linqMinResult = (From r In dt Select r.Field(Of Int32)("Value")).Min‬‬
‫‪Dim linqMaxResult = (From r In dt Select r.Field(Of Int32)("Value")).Max‬‬
‫‪Dim linqAvgResult = (From r In dt Select r.Field(Of Int32)("Value")).Average‬‬
‫)"" ‪Dim computeMinResult = dt.Compute("MIN(Value)",‬‬
‫)"" ‪Dim computeMaxResult = dt.Compute("MAX(Value)",‬‬

‫)"" ‪Dim computeAvgResult = dt.Compute("AVG(Value)",‬‬

‫ربما ٌكون هذا هو الوقت المالئم من أجل قضٌة أخٌرة بما أننً لست خبٌرا بلٌنك فأول ستة استعالمات لٌنك فً هذا‬
‫المقال موجودة فً ‪ msdn‬ومع ذلك فلٌست جمٌع استعالمات لٌنك أنشأت متساوٌة وقد كان من اللطف من زمٌل أن ٌشٌر‬
‫إلى المتغٌر التالً لتجمٌع ‪ max‬الستعراض هذه الحقٌقة‬

‫))"‪Dim linqMaxResult2 = Aggregate r In dt Into Max(r.Field(Of Integer)("value‬‬

‫قمت بتضمٌن نتائج هذا االستعالم فً مخطط للتجمٌع ‪ max‬مسمى )‪ Linq Max (slow‬ستالحظ مع أن االستعالمات‬
‫متكافئة قواعدٌا فاالستعالم الثانً ٌتم تنفٌذه ثالث مرات أبطأ من استعالم لٌنك السابق وسبب الفرق فً األداء هو أن‬
‫النسخة السرٌعة تستخدم نسخة محملة ‪ Overload‬من ‪ max‬ال تحتاج ألي محدد والقاعدة هنا هً ان استخدام ‪Linq to‬‬
‫‪ Dataset‬هو أفضل من استخدام لٌنك تستخدم ‪ select‬بشكل صرٌح ومع فروقات األداء فاالستعالمات تعطً قٌاسات‬
‫متشابهة‬

‫و ال ٌبدو الفائز فً هذه الحالٌة بصورة جلٌة كما ٌتبٌن من المخططات ولكن تمٌل لٌنك ألن تنفذ بشكل أسرع قلٌال من‬
‫أجل ‪ Min‬وأبطأ قلٌال من أجل ‪ max‬و ‪ avg‬وبعد رؤٌة التقدم الكبٌر فً األداء الذي تقدمه لٌنك عند القٌام بالبحث مقارنة‬
‫مع جداول البٌانات توقعت رؤٌة قٌاسات محسنة بشكل أفضل مع داالت التجمٌع‬

‫وفً النهاٌة إن كنت تستخدم جداول البٌانات تعتبر طرٌقة ‪ Select‬أسوأ طرٌقة ٌمكن عملها لتقلٌل تدرجٌة تطبٌقك وقد‬
‫ناقشنا بعض البدائل هنا مثل ‪ Linq‬وفهرسة الجداول حتى نتمكن من استخدام ‪ row.find‬أو تركٌب جدول البٌانات ضمن‬
‫‪ Generic Collection‬فأي من هذه الطرق سوف ٌنفذ األوامر أسرع من االستعالم عن مجموعة من السجالت ذات‬
‫حجم معقول وربما تحتاج لمزاوجة مجموعات السجالت أكثر ما ٌمكن من أجل تسرٌع استعالم وتجمٌع السجالت‬

‫مترجم بتصرف من األصل‬

‫‪http://msdn.microsoft.com/ar-sy/library/dd364983(en-us).aspx‬‬

‫محمد سامر أبو سلو‬

‫خاص بمنتدى فيجول بايزك للعرب‬

‫‪www.vb4arab.com‬‬

You might also like