it-swarm.asia

البحث عن الفهرس مقابل فحص الفهرس

بالنظر إلى خطة تنفيذ استعلام بطيء التشغيل ، لاحظت أن بعض العقد هي بحث عن الفهرس وبعضها عبارة عن مسح للفهرس.

ما الفرق بين البحث عن الفهرس ومسح الفهرس؟

أيهما أفضل؟

كيف يختار SQL واحدًا على الآخر؟

أدرك أن هذا هو 3 أسئلة ولكن أعتقد أن الإجابة على السؤال الأول سوف تشرح الأسئلة الأخرى.

65
Greg

نسخة قصيرة: البحث عن أفضل بكثير

نسخة قصيرة أقل: البحث بشكل عام أفضل كثيرًا ، ولكن العديد من عمليات البحث (الناتجة عن تصميم استعلام سيئ مع استعلامات فرعية مترابطة سيئة على سبيل المثال ، أو لأنك تقوم بإجراء العديد من الاستعلامات في عملية المؤشر أو حلقة أخرى) يمكن أن تكون أسوأ من مسح ، خاصة إذا كان الاستعلام الخاص بك قد ينتهي بإرجاع البيانات من معظم الصفوف في الجدول المتأثر.

يساعد على تغطية الأسرة بأكملها لعمليات البحث عن البيانات لفهم آثار الأداء بشكل كامل.

عمليات مسح الجدول: مع عدم وجود أي فهارس ذات صلة بالاستعلام على الإطلاق ، يضطر المخطط لاستخدام مسح جدول مما يعني أنه يتم النظر في كل صف. يمكن أن يؤدي هذا إلى قراءة كل صفحة تتعلق ببيانات الجدول من القرص والتي غالبًا ما تكون أسوأ حالة. لاحظ أنه بالنسبة لبعض الاستفسارات ، سيستخدم فحص الجدول حتى عند وجود فهرس مفيد - هذا عادة لأن البيانات الموجودة في الجدول صغيرة جدًا لدرجة أنها أكثر صعوبة في اجتياز الفهارس (إذا كانت هذه هي الحالة التي تتوقعها تخطط للتغيير مع نمو البيانات ، بافتراض أن مقياس الانتقائية للمؤشر جيد).

عمليات مسح الفهرس مع عمليات بحث الصف: مع عدم وجود فهرس يمكن استخدامه مباشرة للبحث ، ولكن يوجد فهرس يحتوي على الأعمدة اليمنى يمكن استخدام فحص الفهرس. على سبيل المثال ، إذا كان لديك جدول كبير به 20 عمودًا مع فهرس على العمود 1 ، col2 ، col3 وأصدرت SELECT col4 FROM exampletable WHERE col2=616 ، في هذه الحالة ، فإن فحص الفهرس للاستعلام col2 أفضل من مسح طاولة كاملة. بمجرد العثور على الصفوف المتطابقة ، يجب قراءة صفحات البيانات لالتقاط col4 للإخراج (أو مزيد من الانضمام) وهو ما تكون عليه مرحلة "البحث عن إشارة مرجعية" عندما تراها في خطط الاستعلام.

عمليات مسح الفهرس بدون عمليات بحث الصف: إذا كان المثال أعلاه SELECT col1, col2, col3 FROM exampletable WHERE col2=616 فلن تكون هناك حاجة إلى الجهد الإضافي لقراءة صفحات البيانات: بمجرد العثور على صفوف الفهرس المطابقة col2=616 البيانات المطلوبة معروفة. هذا هو السبب في أنك ترى في بعض الأحيان أعمدة لن يتم البحث عنها مطلقًا ، ولكن من المحتمل أن تتم مطالبتها بالإخراج ، وإضافتها إلى نهاية الفهارس - يمكنها حفظ عمليات بحث الصف. عند إضافة أعمدة إلى فهرس لهذا السبب وهذا السبب فقط ، أضفها باستخدام البند INCLUDE لإخبار المحرك أنه لا يحتاج إلى تحسين تخطيط الفهرس للاستعلام بناءً على هذه الأعمدة (يمكن أن يؤدي ذلك إلى تسريع التحديثات التي تم إجراؤها على هذه الأعمدة). يمكن أن تنتج عمليات مسح الفهرس من الاستعلامات بدون عبارات تصفية أيضًا: SELECT col2 FROM exampletable سيقوم بفحص هذا المثال للفهرس بدلاً من صفحات الجدول.

يبحث الفهرس (مع أو بدون عمليات البحث عن الصف) : في البحث لا يتم اعتبار كل الفهرس. بالنسبة للاستعلام SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567 يمكن لمحرك الاستعلام العثور على الصف الأول الذي سيطابق عن طريق البحث على أساس الشجرة في الفهرس على c1 ثم يمكنه التنقل في الفهرس حتى يصل إلى نهاية النطاق (هذا هو نفسه مع استعلام لـ c1=1234 حيث قد يكون هناك العديد من الصفوف المطابقة للشرط حتى لعملية =). هذا يعني أنه يجب قراءة صفحات الفهرس ذات الصلة فقط (بالإضافة إلى بعض الصفحات المطلوبة للبحث الأولي) بدلاً من كل صفحة في الفهرس (أو الجدول).

الفهارس العنقودية: باستخدام فهرس مجمع ، يتم تخزين بيانات الجدول في العقد الورقية لهذا الفهرس بدلاً من أن تكون في بنية كومة منفصلة. هذا يعني أنه لن تكون هناك حاجة أبدًا إلى أي بحث إضافي عن الصف بعد العثور على الصفوف باستخدام هذا الفهرس بغض النظر عن الأعمدة المطلوبة [ما لم يكن لديك بيانات خارج الصفحة مثل أعمدة TEXT أو VARCHAR(MAX) أعمدة تحتوي على بيانات طويلة].

يمكن أن يكون لديك فهرس مجمع واحد فقط لهذا السبب[1]، الفهرس المجمع is جدولك بدلاً من أن يكون له بنية كومة منفصلة ، لذلك إذا كنت تستخدم واحدًا[2] اختار مكان وضعه بعناية من أجل الحصول على أقصى قدر من المكاسب.

لاحظ أيضًا أن الفهرس العنقودي لأن "مفتاح التجميع" للجدول ومضمن في كل فهرس غير عنقودي على الجدول ، لذا فإن الفهرس ذي التجميع الواسع ليس فكرة جيدة بشكل عام.

[1] في الواقع ، أنت can لديك بالفعل العديد من الفهارس المجمعة عن طريق تحديد الفهارس غير العنقودية التي تغطي أو تشمل كل عمود في الجدول ، ولكن هذا على الأرجح أن تكون مسرفًا للفضاء له تأثير على أداء الكتابة ، لذلك إذا كنت تفكر في القيام بذلك ، فتأكد من أنك بحاجة فعلاً لذلك.

[2] عندما أقول "إذا كنت تستخدم فهرسًا مجمعًا" ، فلاحظ أنه يوصى عمومًا بأن يكون لديك do واحدًا في كل جدول. هناك استثناءات كما هو الحال مع جميع القواعد العامة ، والجداول التي لا ترى سوى بخلاف الإدخالات المجمعة والقراءات غير المرتبة (ربما تكون الجداول المرحلية لعمليات ETL) هي المثال المضاد الأكثر شيوعًا.

نقطة إضافية: عمليات المسح غير الكاملة:

من المهم أن تتذكر أنه وفقًا لبقية الاستعلام ، قد لا يقوم مسح الجدول/الفهرس بالفعل بفحص الجدول بالكامل - إذا كان المنطق يسمح لخطة الاستعلام فقد تكون قادرة على التسبب في إجهاضها مبكرًا. أبسط مثال على ذلك هو SELECT TOP(1) * FROM HugeTable - إذا نظرت إلى خطة الاستعلام لذلك سترى أنه تم إرجاع صف واحد فقط من الفحص وإذا شاهدت IO = إحصاءات (SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable) سترى أنه يقرأ عددًا صغيرًا جدًا من الصفحات (ربما صفحة واحدة فقط).

يمكن أن يحدث نفس الشيء إذا كان من الممكن تشغيل مسند الفقرة WHERE أو JOIN ... ON بالتزامن مع الفحص الذي هو المصدر إذا كانت بياناته. يمكن أن يكون مخطط/عداء الاستعلام ذكيًا في بعض الأحيان بشأن دفع المسندات مرة أخرى نحو مصادر البيانات للسماح بالإنهاء المبكر للمسح الضوئي بهذه الطريقة (وأحيانًا أنت يمكن أن يكون ذكيًا في إعادة ترتيب الاستعلامات لمساعدته على القيام بذلك وبالتالي!). بينما تتدفق data من اليمين إلى اليسار وفقًا للأسهم في عرض خطة الاستعلام القياسية ، يتم تشغيل logic من اليسار إلى اليمين وكل خطوة ( من اليمين إلى اليسار) ليس بالضرورة أن يتم تشغيله حتى يكتمل قبل أن يبدأ التالي. في المثال البسيط أعلاه ، إذا نظرت إلى كل كتلة في خطة الاستعلام كوكيل ، فإن وكيل SELECT يطلب من وكيل TOP صفًا يسأل بدوره وكيل TABLE SCAN لأحدهم ، ثم يطلب وكيل SELECT وكيلًا آخر لكن وكيل TOP يعرف أنه لا داعي للقلق حتى لطلب قارئ الجدول ، يحصل وكيل SELECT على الرد "لا يوجد صلة بالموضوع" ويعلم أن كل العمل قد تم. العديد من العمليات تمنع هذا النوع من التحسين بالطبع في كثير من الأحيان في أمثلة أكثر تعقيدًا فحص جدول/فهرس حقًا هل قراءة كل صف ، ولكن احذر من القفز إلى استنتاج مفاده أن أي فحص يجب أن يكون عملية مكلفة.

76
David Spillett

بشكل عام ، تسعى جيدة ، والمسح الضوئي سيئة.

البحث عن الأماكن التي يكون فيها الاستعلام قادرًا على الاستخدام الفعال للفهرس ، واستخدامه للعثور على الصفوف التي يحتاجها.

عمليات المسح هي المكان الذي يبحث فيه الاستعلام من خلال الفهرس بأكمله محاولًا العثور على ما يحتاجه.

كيف تختار SQL؟ في أعماق الأجزاء الداخلية من مُحسِّن الاستعلام ، يتم اتخاذ القرار بناءً على استعلامك والفهارس المتاحة والمعلومات الإحصائية المرتبطة بهذه الفهارس.

هناك عدد قليل من الكتب لقراءتها قد تكون ذات فائدة هنا - كلاهما من مكتبة ريد جيت في http://www.red-gate.com/community/books/

  • خطط تنفيذ SQL Server بواسطة Grant Fritchey
  • داخل محسن الاستعلام من قبل بنيامين نيفاريز
  • إحصائيات خادم SQL من قبل هولجر شميلينج
6
Thomas Rushton

إذا كنت ترغب في حفر الموضوع ، فإن كتابًا مفيدًا للغاية (على الأقل بالنسبة لي) هو خطط تنفيذ SQL Server بواسطة Grant Fritchey ، وهو متاح مجانًا في RedGate هنا .

إذا كان لديك استفسار مثل

SELECT *
FROM myTable

من المحتمل أن يستخدم SQL Server فحص فهرس ، حيث يحتاج إلى المرور بجميع الصفوف لعرض النتائج المطلوبة.

على العكس تماما،

SELECT *
FROM myTable
WHERE myID = 1

سيؤدي بالتأكيد إلى البحث عن مؤشر. سيستخدم SQL Server بنية B-tree من فهرس myID وسيكون استرداد الخط المناسب أسرع بكثير.

5
KookieMonster

وقد حدد آخرون جيدًا ما يكفي من الاختلافات بين البحث والمسح. في هذه الحالة ، يجب أن يمنحك الاستعلام نفسه ومخطط التنفيذ المعلومات التي تحتاجها لمعرفة القيم المستخدمة كمسندات (عوامل تصفية) للاستعلام في كل جزء. عادةً ما يكون من الأفضل دائمًا إضافة فهارس غير مجمعة على المفاتيح الخارجية ، واعتمادًا على حالات الاستخدام في رمز البرنامج ، قد ترغب في النظر في إنشاء فهارس متعددة الأعمدة أو فهارس أعمدة مضمنة أيضًا. مع المصطلحات المعروضة هنا ، سيعطي بحث google نتائج لائقة على أمثلة لكل منها.

ولكن كمثال ، لنفترض أن الشفرة الخاصة بك تستفسر عن العمود A والعمود B في فلاتر معينة ، ولكنك تريد أيضًا إرجاع قيم العمود C والعمود E ، قد ترغب في إنشاء فهرس على العمود A و B باستخدام INCLUDE الخيار الذي يحتوي على العمود C و E. وبهذه الطريقة سيعيد البحث في فهرس واحد كل ما تحتاجه ، حيث لا توجد حاجة لإجراء بحث لاسترداد القيم الأخرى (C و E) في الصف نفسه.

5
Kahn