سؤال

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

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

ولدي فهرس على EmployeeTypeId هل لا يزال خادم SQL يستخدم هذا الفهرس؟

هل كانت مفيدة؟

المحلول

نعم هذا صحيح.إذا كان جدول الموظفين الخاص بك يحتوي على 10000 سجل، و5 سجلات فقط تحتوي على معرف نوع الموظف في (1،2،3)، فمن المرجح أن يستخدم الفهرس لجلب السجلات.ومع ذلك، إذا وجد أن 9000 سجل تحتوي على معرف الموظف في (1،2،3)، فمن المرجح أن يقوم فقط بإجراء فحص للجدول للحصول على معرفات الموظف المقابلة، حيث أنه من الأسرع مجرد تشغيل الجدول بأكمله بدلاً من الانتقال إلى كل فرع من فروع شجرة الفهرس وانظر إلى السجلات بشكل فردي.

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

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

بافتراض أن الفهرس الموجود في الحقل "EmployeeTypeId" يسمى Index_EmployeeTypeId.

نصائح أخرى

عادةً ما يتم ذلك، ما لم تغطي جملة IN جزءًا كبيرًا من الجدول، وبعد ذلك سيتم إجراء فحص للجدول.أفضل طريقة لمعرفة حالتك المحددة هي تشغيلها في محلل الاستعلام والتحقق من خطة التنفيذ.

ما لم تتحسن التكنولوجيا بطرق لا يمكنني تخيلها مؤخرًا، فإن الاستعلام "IN" الموضح سينتج نتيجة تكون فعليًا عبارة عن عملية OR لثلاث مجموعات نتائج، واحدة لكل من القيم الموجودة في القائمة "IN".تصبح جملة IN شرط مساواة لكل قائمة وستستخدم فهرسًا إذا كان ذلك مناسبًا.في حالة المعرفات الفريدة والجدول الكبير بدرجة كافية، أتوقع أن يستخدم المُحسِّن فهرسًا.

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

من المحتمل أن يكون الأمر موضع نقاش - من المحتمل أن يكون شيء مثل جدول الموظف صغيرًا بما يكفي ليظل مخبأًا في الذاكرة وربما لن تلاحظ فرقًا بين ذلك وبين الاسترجاع المفهرس على أي حال.

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

إذن ، هناك احتمال أن يقوم بند "In" بإجراء فحص طاولة ، لكن المحسن سيحاول العمل على أفضل طريقة للتعامل معه؟

لا يختلف ما إذا كان يتم استخدام الفهرس كثيرًا على نوع الاستعلام بقدر ما يختلف نوع البيانات وتوزيعها في الجدول (الجداول)، ومدى تحديث إحصائيات الجدول، ونوع البيانات الفعلي للعمود .

الملصقات الأخرى صحيحة في أنه سيتم استخدام الفهرس عبر مسح الجدول إذا:

  • لن يصل الاستعلام إلى أكثر من نسبة معينة من الصفوف المفهرسة (على سبيل المثال ~ 10٪ ولكن يجب أن تختلف بين أنظمة إدارة قواعد البيانات).
  • وبدلاً من ذلك، إذا كان هناك الكثير من الصفوف، ولكن هناك عدد قليل نسبيًا من القيم الفريدة في العمود، فقد يكون من الأسرع أيضًا إجراء فحص للجدول.

المتغير الآخر الذي قد لا يكون واضحًا هو التأكد من أن أنواع بيانات القيم التي تتم مقارنتها هي نفسها.في PostgreSQL، لا أعتقد أنه سيتم استخدام الفهارس إذا كنت تقوم بالتصفية على شكل عائم ولكن العمود الخاص بك يتكون من ints.هناك أيضًا بعض العوامل التي لا تدعم استخدام الفهرس (مرة أخرى، في PostgreSQL، يكون عامل التشغيل ILIKE هكذا).

كما هو مذكور، تحقق دائمًا من محلل الاستعلام عندما تكون في شك، وستكون وثائق نظام إدارة قواعد البيانات (DBMS) صديقتك.

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

مع NHibernate، يمكنك كتابة جملة مثل هذا:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

يقوم NHibernate بعد ذلك بإنشاء استعلام يبدو كذلك

select * from employee where employeeid in (1, 5, 23463, 32523)

لذا، كما أشرت أنت وآخرون، يبدو أنه ستكون هناك أوقات سيتم فيها استخدام الفهرس أو إجراء فحص للجدول، ولكن لا يمكنك تحديد ذلك حقًا حتى وقت التشغيل.

Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

سيتم البحث في هذا الاستعلام باستخدام الفهرس الذي قمت بإنشائه.إنه يعمل بالنسبة لي.من فضلك قم بالمحاولة..

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top