Dizin oluştururken neden INCLUDE yan tümcesini kullanıyorsunuz?


432

70-433 sınavı için çalışırken ben aşağıdaki iki yoldan biriyle kapsayan bir dizin oluşturabilirsiniz fark ettim.

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

- VEYA -

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

INCLUDE yan tümcesi benim için yeni. Neden kullanıyorsunuz ve INCLUDE yan tümcesi olan veya olmayan bir kaplama dizini oluşturulup oluşturulmayacağını belirlemede hangi yönergeleri önerirsiniz?

Yanıtlar:


364

Sütun, içinde değil WHERE/JOIN/GROUP BY/ORDER BY, yalnızcaSELECT yan tümcedeki .

INCLUDEFıkra oldukça endeks ağacında daha düşük / yaprak düzeyinde verileri ekler. Bu, dizini daha küçük yapar, çünkü ağacın bir parçası değildir

INCLUDE columnsdizindeki anahtar sütunlar değildir, bu nedenle sıralanmazlar. Bu, yukarıda bahsettiğim gibi tahminler, sıralama vb. İçin gerçekten yararlı olmadığı anlamına gelir. Ancak, anahtar sütun (lar) dan birkaç satıra kalan bir aramaya sahip olmanız faydalı olabilir

Çalışılan bir örneği içeren başka bir MSDN makalesi


7
Öyleyse, bu, kapalı bir dizinin daha ucuz bir sürümünü oluşturmak için bir teknik olurdu?
JMarsch

3
@gbn, bu cümleyi daha ayrıntılı olarak açıklar mısın, ve içerme yantümcesinin sıralama, vb. için neden yararlı olmadığı anlamına gelir mi? "INCLUDE yan tümcesi, verileri dizin ağacından ziyade en düşük / yaprak düzeyinde ekler Bu endeksi
küçültür

4
@JMarsch: geç cevap için özür dilerim, ama evet, tam olarak bu.
gbn

10
@Tola Odejayi: INCLUDE sütunları dizindeki anahtar sütunlar değildir, bu nedenle sıralanmazlar. Bu onları genellikle JOIN'ler veya sıralama için yararlı kılmaz. Ve bunlar anahtar sütunlar olmadıklarından, anahtar sütunlar gibi tüm B-ağacı yapısında
oturmazlar

4
Bu en çok kabul edilen cevap olsa da, daha fazla açıklamaya ihtiyaç olduğunu düşünüyorum, bazı sorgular için sütun bir parçasıysa SELECTve bazıları için değilse? \
Chisko

215

Kümelenmemiş bir dizinin yaprak düzeyine bir veya daha fazla sütun eklemek için INCLUDE öğesini kullanırsınız, bunu yaparak sorgularınızı "kapatabilirsiniz".

Bir çalışanın kimliğini, departman kimliğini ve soyadını sorgulamanız gerektiğini düşünün.

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

(EmployeeID, DepartmentID) üzerinde kümelenmemiş bir dizine sahipseniz, belirli bir departmanın çalışanlarını bulduktan sonra, gerçek soyadı sütununu almak için gerçek tam çalışan kaydını almak için şimdi "yer işareti araması" yapmanız gerekir. . Çok sayıda çalışan bulursanız, performans açısından oldukça pahalı olabilir.

Bu soyadını dizininize eklediyseniz:

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

ihtiyacınız olan tüm bilgiler kümelenmemiş dizinin yaprak düzeyinde bulunur. Sadece kümelenmemiş indekse bakarak ve belirli bir departman için çalışanlarınızı bularak, gerekli tüm bilgilere sahip olursunuz ve endekste bulunan her çalışan için yer imi araması artık gerekli değildir -> çok zaman kazanırsınız.

Açıkçası, kümelenmemiş her dizine her sütunu ekleyemezsiniz - ancak "kapsanması" (ve çok fazla kullanılması) için yalnızca bir veya iki sütunu eksik sorgularınız varsa, bunları dahil etmek çok yararlı olabilir. uygun bir kümelenmemiş endeks haline getirilir.


25
Bu dizini kullanmak istediğinizden emin misiniz? Neden ÇalışanNo? Anahtar sütunlarda yalnızca DepartmentID'ye ihtiyacınız var mı? Burada yetkili olarak alıntılandınız: stackoverflow.com/q/6187904/27535
gbn

3
Açıklamanız iyi, ancak aslında belirttiğiniz kullanım durumuna uymuyor. Anahtar sütun (lar) filtre üzerinde veya JOINsorgudaki anahtarlarda olmalı ve INCLUDEs, aldığınız ancak sıralamamış olan veriler olmalıdır.
JNK

15
Her şeyden önce, Employee (EmployeeID, DepartmentID) endeksi DepartmentID = 5'i filtrelemek için kullanılmayacaktır. Çünkü sırası
uyuşmuyor

29

Bu tartışma önemli noktayı kaçırıyor: Soru, "anahtar olmayan sütunlar" ın index- columns veya dahil olarak dahil edilmesi daha iyi olup olmadığı değildir. edilmesi olmadığı değildir.

Soru, dizinde gerçekten gerekli olmayan sütunları dahil etmek için include-mekanizmasını kullanmanın ne kadar pahalı olduğudur ? (tipik olarak nerede cümleciklerinin bir parçası değildir, ancak genellikle seçimlere dahil edilir). Yani ikileminiz daima:

  1. Yalnızca id1, id2 ... idN'de dizin kullanın veya
  2. İd1, id2 ... idN'de dizin kullan ve col1, col2 ... colN'yi ekle

Nerede: id1, kimlik2 ... IDN sıklıkla kısıtlamalar ve col1, col2 ... Coln kolonlar genellikle seçilir kullanılan sütunlar vardır, ama genellikle değil kısıtlamalar kullanılan

(Bu sütunların tümünü dizin anahtarının bir parçası olarak dahil etme seçeneği her zaman saçmadır (kısıtlamalarda da kullanılmadıkları sürece) - çünkü dizinin güncellenmesi ve sıralanması gerektiğinde sıralanması gerektiğinden her zaman daha pahalı olur "anahtarlar" değişmedi).

Seçenek 1 veya 2'yi mi kullanıyorsunuz?

Cevap: masanız nadiren güncellenir ise - çoğunlukla gelen / yerleştirilen silindi - - o zaman bazı "sıcak sütunlar" (ancak bu genellikle seçer kullanılan içerecek şekilde dahil-mekanizmasını kullanmak nispeten ucuz olduğu değil çünkü çoğu zaman kısıtlamalar kullanılan) ekler / silmeler, dizinin yine de güncellenmesini / sıralanmasını gerektirir ve bu nedenle, dizini zaten güncellerken birkaç ek sütunun depolanmasıyla çok az ek yük oluşur. Ek yük, dizinde yedek bilgi depolamak için kullanılan fazladan bellek ve CPU'dur.

Dahil edilen sütunlar olarak eklemeyi düşündüğünüz sütunlar genellikle güncellenirse ( index- key -columns güncellenmeden) - veya - eğer dizin çok fazla olursa, tablonuzun bir kopyasına yakın olur - seçenek 1'i kullanın Ben öneririm! Ayrıca, belirli bir ekleme sütunu / sütunları eklemek, performans farkı yaratmazsa - bunları ekleme fikrini atlamak isteyebilirsiniz :) Yararlı olduklarını doğrulayın!

Anahtarlarda (id1, id2 ... idN) aynı değerler başına ortalama satır sayısı da önemli olabilir.

Kısıtlamaya dahil edilen bir dizin sütunu olarak eklenen bir sütunun kısıtlamada kullanıldığına dikkat edin : Böyle bir dizin kullanılabildiği sürece (index- key -columns'a karşı kısıtlamaya dayalı olarak ) - SQL Server eşleşiyorsa tablonun kendisinde pahalı yoldan gitmek yerine dizine (yaprak-düğüm-değerleri) karşı sütun kısıtlaması.


18

Temel dizin sütunları sıralanır, ancak dahil edilen sütunlar sıralanmaz. Bu, kaynakları bir dizini kapsayacak şekilde korurken, içerilen sütunlardaki verilerin bir sorguyu kapsamasını sağlamayı mümkün kılar. Bu nedenle, sorguları kapsamak istiyorsanız, dizinin sıralı sütunlarına satırları bulmak için arama ölçütlerini koyabilir, ancak daha sonra arama dışı veriler içeren ek, sıralanmamış sütunları "dahil edebilirsiniz". Dizin bakımında sıralama ve parçalanma miktarını azaltmaya kesinlikle yardımcı olur.


7

Sebepler (endeksin yaprak seviyesindeki veriler dahil) iyi açıklanmıştır. Bu konuda iki sarsıntı vermenizin nedeni, sorgunuzu çalıştırdığınızda, ek sütunlarınız yoksa (SQL 2005'te yeni özellik) SQL Server'ın ek sütunları almak için kümelenmiş dizine gitmesi gerektiğidir bu da daha fazla zaman alır ve SQL Server hizmetine, disklere ve yeni veri sayfaları belleğe yüklenirken belleğe (tampon önbellek) daha fazla yük ekler ve potansiyel olarak daha sık ihtiyaç duyulan diğer verileri arabellek önbelleğinden çıkarır.


aslında daha az bellek kullandığını kanıtlamanın bir yolu var mı? Ben de bu ne beklenir ama iş yerinde bu konuda bazı statik alıyorum
Asken

Sayfayı yığın veya kümelenmiş dizinden belleğe ve dizin sayfasını yüklemeniz gerektiği düşünüldüğünde, yinelenen verileri belleğe koyduğunuz anlamına gelir matematik oldukça basit hale gelir. Özel olarak ölçmenin bir yoluna gelince, hayır yok.
mrdenny

5

Daha önce verilen cevaplarda görmediğim başka bir husus, dahil edilen sütunların varchar (max) gibi dizin anahtar sütunları olarak izin verilmeyen veri türlerinden olabileceğidir.

Bu, bu tür sütunları bir kaplama dizinine eklemenizi sağlar. Son zamanlarda yararlı bir dizin ile SELECT sütunları çok olan bir nHibernate oluşturulan sorgu sağlamak için bunu yapmak zorunda kaldı.


3

INCLUDEAnahtarda bu sütuna ihtiyacınız yoksa , anahtar sütunları tercih etmenin bir nedeni de belgelerdir. Bu, gelişen endeksleri gelecekte çok daha kolay hale getiriyor.

Örneğiniz düşünüldüğünde:

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

Sorgunuz şöyle görünüyorsa bu dizin en iyisidir:

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

Tabii ki INCLUDE, anahtar parçalara sahip olmaktan ek bir fayda elde edebiliyorsanız , sütunları koymamalısınız. Aşağıdaki sorguların her ikisi de aslında col2dizinin anahtarındaki sütunu tercih eder .

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

En şudur varsayalım değil durum ve sahip olduğumuz col2içinde INCLUDEendeksinin ağaç kesiminde böyle bir çözüme sahip sadece hayır faydası olduğundan maddesi.

Birkaç yıl ileri git.

Bu sorguyu ayarlamanız gerekiyor:

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

Bu sorguyu optimize etmek için aşağıdaki dizin harika olur:

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

Bu tabloda zaten hangi dizinlerin bulunduğunu kontrol ederseniz, önceki dizininiz hala orada olabilir:

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

Şimdi bunu biliyorsunuz Col2ve Col3dizin ağacının bir parçası değilsiniz ve bu nedenle okuma dizin aralığını daraltmak veya satırları sıralamak için kullanılmıyor. another_columnDizinin anahtar bölümünün sonuna eklemek oldukça güvenlidircol1 ) . Herhangi bir şeyi kırma riski çok azdır:

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

Bu endeks daha da büyüyecek ve hala bazı riskleri var, ancak mevcut endeksleri yenilerini tanıtmaya kıyasla genişletmek genellikle daha iyidir.

Olmadan bir dizine sahip olsaydınız, hemen ardından INCLUDEekleyerek hangi sorguları kıracağınızı bilemezdiniz .another_colCol1

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

Eklemek ne olur another_colarasında Col1veCol2 ? Diğer sorgular acı çekecek mi?

Bu sütunları tablodan getirmekten kaçınmak için eklerseniz,INCLUDE anahtar sütunlara karşı diğer "avantajları" vardır . Ancak, dokümantasyon yönünü en önemlisi olarak görüyorum.

Soruna cevap vermek için:

INCLUDE yan tümcesi olan veya olmayan bir kaplama dizini oluşturulup oluşturulmayacağını belirlemede hangi yönergeleri önerirsiniz?

Yalnızca sütunu, dizini tabloyu ziyaret etmeden dizinde kullanabilmek amacıyla dizine bir sütun eklerseniz, onu INCLUDEyan tümceye yerleştirin.

Sütunu dizin anahtarına eklemek ek yararlar getirirse (örneğin order by, okunan dizin aralığını daraltabileceği için veya bu anahtar için) anahtarı ekleyin.

Bununla ilgili daha uzun bir tartışmayı buradan okuyabilirsiniz:

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


2

Dizin tanımına yerleştirilmiş tüm sütunların toplam boyutunda bir sınır vardır. Bununla birlikte, bu kadar geniş bir indeks oluşturmak zorunda kalmadım. Benim için en büyük avantaj, belirli bir sırada tanımlanmaları gerekmediği için sütunları içeren bir dizinle daha fazla sorguyu kapsayabilmenizdir. Düşünmek dizin içindeki bir dizin olarak. Bir örnek StoreID (burada StoreID düşük seçiciliğe sahiptir, yani her mağazanın birçok müşteriyle ilişkilendirildiği anlamına gelir) ve ardından müşteri demografi verileri (LastName, FirstName, DOB): Bu sütunları yalnızca bu sırayla satır içine alırsanız (StoreID, LastName , FirstName, DOB), yalnızca StoreID ve LastName bildiğiniz müşterileri verimli bir şekilde arayabilirsiniz.

Öte yandan, StoreID üzerindeki dizini tanımlamak ve LastName, FirstName, DOB sütunlarını dahil etmek, aslında StoreID'de iki arama dizini yüklemesi yapmanıza ve ardından dahil edilen sütunlardan herhangi birinde yüklem aramanıza olanak tanır. Bu, StoreID ile başladığı sürece tüm olası arama permütasyonlarını kapsamanıza izin verir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.