it-swarm.asia

لماذا استخدام جملة INCLUDE عند إنشاء فهرس؟

أثناء الدراسة لامتحان 70-433 ، لاحظت أنه يمكنك إنشاء فهرس تغطية بإحدى الطريقتين التاليتين.

CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)

- OR -

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

جملة INCLUDE جديدة بالنسبة لي. لماذا تستخدمه وما هي الإرشادات التي تقترحها في تحديد ما إذا كنت تريد إنشاء فهرس تغطية مع أو بدون جملة INCLUDE؟

397
Cory

إذا كان العمود غير موجود في WHERE/JOIN/GROUP BY/ORDER BY ، ولكن فقط في قائمة الأعمدة في جملة SELECT.

تضيف جملة INCLUDE البيانات عند المستوى الأدنى/الورقة بدلاً من شجرة الفهرس. هذا يجعل الفهرس أصغر لأنه ليس جزءًا من الشجرة

INCLUDE columns ليست أعمدة رئيسية في الفهرس ، لذا فهي غير مرتبة. هذا يعني أنها ليست مفيدة حقًا للمسندات والفرز وما إلى ذلك كما ذكرت أعلاه. ومع ذلك ، سيكون may مفيدًا إذا كان لديك بحث متبقٍ في صفوف قليلة من عمود (أعمدة) المفاتيح

مقالة MSDN أخرى مع مثال عمل

338
gbn

يمكنك استخدام INCLUDE لإضافة عمود واحد أو أكثر إلى مستوى الورقة لفهرس غير عنقودي ، وإذا كان ذلك ، فيمكنك "تغطية" استفساراتك.

تخيل أنك بحاجة إلى الاستعلام عن معرف الموظف ومعرف القسم واسم العائلة.

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

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

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

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

ثم كل المعلومات التي تحتاجها متوفرة في مستوى ورقة الفهرس غير عنقودية. فقط من خلال البحث في الفهرس غير العنقودي والعثور على موظفيك لقسم معين ، لديك كل المعلومات اللازمة ، ولم يعد البحث عن إشارة مرجعية لكل موظف موجود في الفهرس ضروريًا -> يمكنك توفير الكثير من الوقت.

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

207
marc_s

تفتقد هذه المناقشة إلى النقطة المهمة: السؤال ليس ما إذا كان من الأفضل تضمين "الأعمدة غير الرئيسية" كأعمدة فهرس - أو كأعمدة مضمنة -.

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

  1. استخدم الفهرس على id1 ، id2 ... idN وحده أو
  2. استخدم الفهرس على id1 ، id2 ... idN plus include col1 ، col2 ... colN

حيث: id1 ، id2 ... idN عبارة عن أعمدة تستخدم غالبًا في القيود و col1 ، col2 ... colN عبارة عن أعمدة يتم تحديدها غالبًا ، ولكن عادةً لا تستخدم في القيود

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

لذا استخدم الخيار 1 أو 2؟

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

إذا كانت الأعمدة التي تفكر في إضافتها كأعمدة مضمنة يتم تحديثها غالبًا (بدون الفهرس - المفتاح - يتم تحديث الأعمدة) - أو - إذا كان الكثير منهم يصبح الفهرس قريبًا من نسخة من الجدول الخاص بك - استخدام الخيار 1 أود أن أقترح! أيضًا إذا تبين أن إضافة عمود (أعمدة) معينة لا يحدث فرقًا في الأداء - فقد ترغب في تخطي فكرة إضافتها :) تحقق من أنها مفيدة!

يمكن أن يكون متوسط ​​عدد الصفوف لكل نفس القيم في المفاتيح (id1 ، id2 ... idN) ذا أهمية أيضًا.

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

22
Fredrik Solhaug

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

17
onupdatecascade

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

6
mrdenny

وهناك اعتبار إضافي لم أره في الإجابات المقدمة بالفعل ، وهو أن الأعمدة المضمنة يمكن أن تكون من أنواع البيانات غير المسموح بها كأعمدة مفتاح فهرس ، مثل varchar (بحد أقصى).

يتيح لك هذا تضمين هذه الأعمدة في فهرس التغطية. كان عليّ القيام بذلك مؤخرًا لتقديم استعلام nHibernate الذي تم إنشاؤه ، والذي كان يحتوي على الكثير من الأعمدة في SELECT ، مع فهرس مفيد.

5
Robin Hames

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

من ناحية أخرى ، فإن تعريف الفهرس على StoreID بما في ذلك أعمدة LastName و FirstName و DOB من شأنه أن يتيح لك في جوهره القيام ببحثين عن الفهرسة على StoreID ومن ثم البحث عن أي من الأعمدة المضمنة. سيتيح لك ذلك تغطية جميع عمليات البحث الممكنة طالما أنه يبدأ بـ StoreID.

2
mEmENT0m0RI

أحد أسباب تفضيل INCLUDE على أعمدة المفاتيح إذا كنت لا تحتاج إلى هذا العمود في المفتاح هو التوثيق. هذا يجعل الفهارس المتطورة أكثر سهولة في المستقبل.

النظر في المثال الخاص بك:

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

هذا الفهرس هو الأفضل إذا كان الاستعلام الخاص بك يبدو كالتالي:

SELECT col2, col3
  FROM MyTable
 WHERE col1 = ...

بالطبع يجب ألا تضع الأعمدة في INCLUDE إذا كان يمكنك الحصول على فائدة إضافية من وجودها في الجزء الرئيسي. يفضل كلا الاستعلامات التالية في الواقع العمود col2 في مفتاح الفهرس.

SELECT col2, col3
  FROM MyTable
 WHERE col1 = ...
   AND col2 = ...
SELECT TOP 1 col2, col3
  FROM MyTable
 WHERE col1 = ...
 ORDER BY col2

لنفترض أن هذا هو لا الحالة ولدينا col2 في جملة INCLUDE لأنه لا يوجد أي فائدة من وجودها في جزء الشجرة من الفهرس.

سريع إلى الأمام بعض السنوات.

تحتاج إلى ضبط هذا الاستعلام:

SELECT TOP 1 col2
  FROM MyTable
 WHERE col1 = ...
 ORDER BY another_col

لتحسين هذا الاستعلام ، سيكون الفهرس التالي رائعًا:

CREATE INDEX idx1 ON MyTable (Col1, another_col) INCLUDE (Col2)

إذا قمت بفحص الفهارس الموجودة في هذا الجدول بالفعل ، فقد لا يزال هناك فهرس سابق:

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

أنت تعرف الآن أن Col2 و Col3 ليسا جزءًا من شجرة الفهرس وبالتالي لا يتم استخدامهما لتضييق نطاق فهرس القراءة ولا لترتيب الصفوف. آمن إلى حد ما لإضافة another_column إلى نهاية جزء مفتاح الفهرس (بعد col1). هناك خطر ضئيل لكسر أي شيء:

DROP INDEX idx1 ON MyTable;
CREATE INDEX idx1 ON MyTable (Col1, another_col) INCLUDE (Col2, Col3);

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

إذا كان لديك فهرس بدون INCLUDE ، فلن تتمكن من معرفة الاستعلامات التي قد توصّل إليها عن طريق إضافة another_col مباشرة بعد Col1.

CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)

ماذا يحدث إذا أضفت another_col بين Col1 و Col2؟ هل ستعاني استفسارات أخرى؟

هناك "فوائد" أخرى لـ INCLUDE مقابل الأعمدة الرئيسية إذا أضفت هذه الأعمدة فقط لتجنب جلبها من الجدول . ومع ذلك ، فأنا أعتبر أن جانب التوثيق هو الجانب الأكثر أهمية.

للإجابة على سؤالك:

ما هي الإرشادات التي تقترحها في تحديد ما إذا كنت تريد إنشاء فهرس تغطية مع أو بدون جملة INCLUDE؟

إذا قمت بإضافة عمود إلى الفهرس لغرض وحيد هو إتاحة هذا العمود في الفهرس دون زيارة الجدول ، فضعه في جملة INCLUDE.

إذا أضفت العمود إلى مفتاح الفهرس فوائد إضافية (على سبيل المثال ، order by أو لأنه يمكن أن يضيق نطاق فهرس القراءة) ، فأضفه إلى المفتاح.

يمكنك قراءة مناقشة أطول حول هذا هنا:

https://use-the-index-luke.com/blog/2019-04/include-columns-in-btree-indexes

1
Markus Winand