Dizine eklenecek sütunlar için Sabit ve Hızlı kural


38

Kümelenmemiş dizine hangi sütunların ve hangi sırayla dahil edileceğine karar verilmesine karar verecek sert ve hızlı bir kural var mı? Ben sadece bu yazıyı okuyordum https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index ve aşağıdaki sorgu için şunu buldum:

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

Poster bu şekilde indeks yapmayı önerdi:

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

işte sorum şu, neden bu şekilde indeks yapamıyoruz

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

veya

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

ve posterin Soyadı sütununun dahil edilmesine karar vermesine neden olan şey. Neden diğer sütunlar değil? ve sütunları orada hangi sırayla tutmamız gerektiğine nasıl karar vermeliyiz?


3
DAHİL normalde bir kayıt bulunduktan sonra ihtiyacınız olacak alanlara sahip olmalı ve daha fazla veri almak için geri dönüş yolunda tasarruf etmenizi sağlayacaktır. DAHİL içerisindeki alanların sırası önemli değildir.
Jimbo

Ryk, şahsen ben bu yazıyı yararlı buluyorum.
Jason Young,

Bu soruyu da faydalı buluyorum.
İnsanları

Yanıtlar:


47

Bu marc_s'ın önerisi yanlıştır. Bir yorum ekledim. (Ve benim cevabım da kabul edildi!)

Bu sorgu için dizin

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

Bir dizin genellikle

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Nerede:

  • KeyColList = Anahtar sütunları = satır kısıtlaması ve işlemek için kullanılır.
    WHERE, JOIN, ORDER BY, GROUP BY vb.
  • NonKeyColList = Anahtar olmayan sütunlar = seçim / kısıtlamadan sonra SELECT'te ve toplamada (örn. SUM (col)) kullanılır

+1 - OP'deki örnek indekslerin sorgu için değersiz olduğuna katılıyorum (bkz.
JNK

Harika! sadece bir şey daha KeyColList ve NonKeyColList'in sırasına karar verecek. Benim örneğimle açıklar mısın? Diyelim ki benim sorgum SELECT ÇalışanN, Departman Kimliği, Soyadı'NIN Çalışan Adından SoyadıDİRİM = 5, DevletKimliği = 4 Dizin şimdi nasıl olabilir?

@Rocky - NonKeyColListsipariş önemli değil. KeyColListsıra, sorgularda kullanılmalarını beklediğiniz sıklıkta olmalıdır. Aşağıdaki cevabımdaki notlarıma bakınız ancak Last Name, First Name, Middile Initialbir telefon rehberindeki gibi. İkinci alanı bulmak için ilk alana ihtiyacınız var.
JNK

@gbn Gerçekten dahil etme listesinde Çalışan İçi gerekli mi? ÇalışanKimliği Sütununda kümelenmiş bir dizin varsa ve bunun üzerinde DeptId sütunda kümelenmemiş bir dizin oluşturursak, bu nedenle Kümelenmemiş dizinin zaten Kümelenmemiş Dizin yapısında bulunan kümelenme anahtarına referansı var, INCLUDE listesinde kümelenme anahtarı dahil değil ' t Herhangi bir avantaj eklemek.
Viswanathan Iyer

1
@ViswanathanIyer, gerçek diskteki depolama alanına iki kez eklenmeyecek: SQL Server bunu algılıyor. Bu yüzden gerekli değildir, ancak işleri daha net hale getirir. Ancak, söz konusu kümelenmiş dizinleri bilmiyoruz, bu nedenle hiçbirini varsaymamak daha güvenli.
gbn

19

JNK ve gbn harika cevaplar verdi, ancak aynı zamanda büyük resmi göz önünde bulundurmaya değer - sadece tek bir sorguya odaklanmak değil. Her ne kadar bu özel sorgu bir indeksten (# 1) faydalanabilse de:

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Bu dizin, örneğin sorgu biraz değişirse hiç yardımcı olmuyor:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Bunun endekse ihtiyacı var (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

5. Bölümde 1.000 çalışanınız olduğunu hayal edin. Tüm Smith'leri bulmak için # 1 indeksini kullanarak, dahil edilen sütunlar anahtarın bir parçası olmadığından Bölüm 5'teki tüm 1000 satırı aramanız gerekir. Dizin # 2'yi kullanarak, doğrudan Bölüm 5, Soyadı Smith'i arayabilirsiniz.

Bu nedenle, # 2 No'lu dizin, daha geniş bir sorgu yelpazesine hizmet ederken daha kullanışlıdır - ancak maliyeti, daha fazla şişirilmiş bir indeks anahtarıdır ve bu da endeksin yaprak dışı sayfalarını büyütür. Her sistem farklı olacak, bu yüzden burada hiçbir kural yoktur.


Bir not olarak, eğer Çalışan Kimliği bu tablonun kümelenme anahtarıysa - kümelenmiş bir dizin varsayarak - o zaman Çalışan Kimliği eklemeniz gerekmiyorsa - kümelenmemiş tüm dizinlerde mevcut olması anlamına gelir; olmak

Employee(DepartmentID, LastName)

2
Daha yararlı bilgi için +1. Son noktanız için, bunu test ettim ve Çalışan Kimliği kümelenmiş bir dizinse, INCLUDE içindeki Çalışan Kimliği'nin açıkça kullanılması (dizin büyüklüğüne bağlı olarak) dikkate alınmaz. Düşündüğümden daha açık ve sanırım olumsuz bir yer yok.
gbn

1
Kesinlikle katılıyorum - her zaman açık olmak her zaman daha iyidir, özellikle de hiçbir maliyeti yoksa!

1
Sadece durumda ... Yani, INCLUDE içinde kümelenmiş anahtarı test ettim (Çalışan Kimliği açıkça değil) ve boşluk eklemiyor. Anahtar sütunlarda öyle.
gbn

@gbn Evet, küme anahtarının yalnızca, INCLUDE sütunlarının bulunduğu dizinin yaprak düzeyinde kalması gerekir. İndeks anahtarına taşımak, yaprak olmayan sayfalarda da var olacağı anlamına gelir. Bu birazcık şişkinlikle sonuçlanacak, ancak korkunç bir miktarla sonuçlanmayacak (orta seviye sayfalarda, bir Tamsayı varsayılarak yaprak düzeyinde sayfa başına 4 bayt daha ekleyebilirsiniz).

Bu, bu makalede açıklanan etkilerden bazılarını içeren harika bir cevaptır: sqlperformance.com/2014/07/sql-indexes/… Sorgunuz değişirse, dizinlerinizin gereksinimlerini de yerine getirin. Jim'in cevabından daha iyi olabilirsin, ama @gbn cevabını daha iyi bulabilirsin.
John aka hot2use

7

Bunu ilk nasıl edindiğinizden emin değilim. Benim için bu sorgu için kullanırdım:

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

SQL'de hemen hemen her şey için "Sert ve hızlı kural" yoktur.

Ancak, örneğin, dizinin kullanacağı tek alan DepartmentID, WHEREmaddede olduğu içindir.

Diğer alanların oradan kolayca erişilebilir olması gerekir. O DepartmentIDzamana göre seçersiniz INCLUDE, o alanların dizinin yaprak düğümünde olmasıdır.

Diğer örneklerinizi kullanmak istemezsiniz çünkü bu indeks için işe yaramazlar.

Telefon rehberi gibi bir dizin düşünün. Telefon rehberlerinin çoğu Soyadı, Adı, Orta Adı'na göre sıralanmıştır. Birinin adını, soyadını bilmiyorsanız, telefon rehberi dizininin sırasına göre ilk adı arayamadığınız için telefon rehberi size bir şey yapmaz.

INCLUDEAlanlar kitapta her giriş için telefon vb numarası, adres diğer bilgileri gibidir.

DÜZENLE:

Neden kullanmamaya karar vermek için:

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

Ya varsa bu endeks sadece yararlıdır EmployeeIDya İKİ EmployeeID ve LastNamesizin de WHEREfıkra. Bu hemen hemen bu sorgu için ihtiyaç duyduğunuz şeylerin OPPOSİTESİ .


@ ajbeaven bu doğru, bu yüzden düzenlemeye koyduğum yorumun EITHER çalışanı kimliğine veya her iki sütuna da ihtiyacınız olduğunu söylüyor.
JNK

durr üzgünüm yanlış okunuyor :(
ajbeaven

0

Sanırım (worker_id, department_id) endeksini hala kullanabiliyorsunuz, ancak nerede olduğu gibi şu cümleye 'boş' bir satır eklemeniz gerekecek: "worker_id = worker_id)

  • üzerinde bir indeks olan (çalışan_id, departemnent_id),
  • yalnızca department_id üzerinde arama yapmak / kısıtlamak zorunda
  • Dizini yanlış düzenden beri kullanmayacağını bilmek (ya da şimdiye kadar işler değişti ve şu "numara" artık gerekli değil. Ben bir "oldy"?) .
  • "Eski" numarayı kullan.

    Çalışan emp * seçeneğini
    nerede emp.employee_id = emp.employee_id
    ve emp.department_id = 5

(Yani, Soyadı'nın buraya dahil edilmesine odaklanmıyorum, ama evet / veya anahtarın kullanılmamasına odaklanıyorum.)

Saygılarımla,

Miguell


2
Hayır, bu işe yaramaz ve verimli değil.
ypercubeᵀᴹ

Özellikle, department_id 5'in tüm örneklerini bulmak için her çalışan kimliğini aramak için bir dizin taraması yapması gerekecektir. 1000 çalışan ve 5 departman varsa, SQL, belirli bir departmanın tüm sıralarını bulmak için tüm 1000 çalışanı incelemelidir.
Mark Sowul

Şimdi tam tersini düşünün (index, department_id, worker_id). Belli ki, şimdi belirli bir departmanı bulmak kolaydır, ancak belirli bir çalışanı bulmak için, SQL'in belirli bir çalışanın tüm sıralarını bulmak için yalnızca 5 departmanı taraması gerektiğini unutmayın.
Mark Sowul
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.