Dizinlerdeki sütunların sırası ne kadar önemlidir?


173

Dizin bildiriminin başlangıcında en seçici sütunları koymanız gerektiğini duydum. Misal:

CREATE NONCLUSTERED INDEX MyINDX on Table1
(
   MostSelective,
   SecondMost,
   Least
)

Öncelikle, söylediğim doğru mu? Öyleyse, dizinimdeki sütunların sırasını yeniden düzenleyerek performansta büyük farklılıklar görüyor muyum yoksa daha çok "yapmak güzel" bir uygulama mı?

Sormamın nedeni, DTA aracılığıyla bir sorgu koyduktan sonra, varolan bir dizinle hemen hemen aynı sütunları içeren bir dizin oluşturmamı önerdi, çünkü sadece farklı bir sırayla. Sadece mevcut dizine eksik sütunları ekleyerek ve iyi çağırmayı düşünüyordum. Düşünceler?

Yanıtlar:


193

Bunun gibi bir dizine bakın:

Cols
  1   2   3
-------------
|   | 1 |   |
| A |---|   |
|   | 2 |   |
|---|---|   |
|   |   |   |
|   | 1 | 9 |
| B |   |   |
|   |---|   |
|   | 2 |   |
|   |---|   |
|   | 3 |   |
|---|---|   |

İlk sütunun ilk önce ikinci sütunu kısıtlamaktan daha fazla sonucu nasıl ortadan kaldırdığından, A'yı nasıl kısıtlayacağınızı görün. Dizinin nasıl geçmesi gerektiğini, sütun 1'i, sonra sütun 2'yi vb. Hayal ediyorsanız, yumruk geçişindeki sonuçların çoğunun kesilmesinin 2. adımı çok daha hızlı hale getirdiğini görürsünüz.

Başka bir durum, 3. sütunda sorguladıysanız, sonuç kümelerini daraltmak hiç de yararlı olmadığı için optimize edici dizini bile kullanmaz. Bir sorguda olduğunuzda, bir sonraki adımdan önce ilgilenilecek sonuçların sayısını azaltmak daha iyi performans anlamına gelir.

Dizin de bu şekilde saklandığından, sorgulama yaparken ilk sütunu bulmak için dizinde geri izleme yoktur.

Kısacası: Hayır, gösteri için değil, gerçek performans avantajları var.


13
Yukarıdaki resimde, bu dizinin yalnızca sorguda Sütun 1 belirtilmişse yararlı olacağını unutmayın. Sorgunuz, Katıl veya Arama Tahmininde yalnızca Sütun 2'yi belirtirse, bu yararlı olmaz. Yani düzen de orada önemli. Belki bu söylemeye gerek yok, ama bahsetmek istedim.
CodeCowboyOrg

3
Ayrıca, Dizininizin yukarıdaki resim gibi olduğunu ve sütun1 ve sütun2'deki sorgu filtrelerinizin olduğunu, ancak sütun2'nin daha benzersiz olduğunu ve gerçekten filtrelemek istediğiniz şeyin aslında sütun2 olduğunu varsayalım. sütun 2 önce gelir. Bu mantıksız görünebilir, ancak bir dizinin birkaç sayfada depolandığını ve bir dizi değer içeren bir ağaç olduğunu unutmayın, yukarıdaki Sütun 1 olasılıkların 1 / 2'sini ortadan kaldırırken, dizin zaten hangi dizin sayfasının doğrudan Sütun2 değeri, kümeyi daraltmak için Sütun 1'e gerek yoktur.
CodeCowboyOrg

4
Bu resim, dizinlerin nasıl yapılandırıldığına veya yönlendirildiğine ilişkin doğru bir gösterim değildir. Var bu rektifiye bir cevap sunulan stackoverflow.com/a/39080819/73226
Martin Smith

6
@MartinSmith Yanlış olduğunu kabul etmiyorum. Kabul etmek son derece basitleştirilmiş, niyetim buydu. Bununla birlikte, seviyeler hakkında daha fazla ayrıntıya girme cevabınız, daha derinlere inmek isteyenler için takdir edilmektedir. Ağaç görüntünüze bakarsanız, neyi açıkladığımı çok basit bir şekilde göreceksiniz . Bu çok benzersiz ve hatta SQL'e özgü değildir; B-ağacı indeksleme pek çok şey arasında oldukça yaygındır.
Nick Craver

@MartinSmith Ayrıca, yanlış olduğunu da kabul etmiyorum, tanımladığınız şey, dizin kapsamına nasıl ulaşacağınızın standart davranışıdır - aralık sorgularını gerçekleştirdiğinizde seçicilik çok daha önemlidir, çünkü bu, optimize edicinin dizin sayfası sayısını en aza indirir taraması gerekir; Bu, milyonlarca satır içeren büyük tablolarda önemli olabilir
Paul Hatcher

127

Sütunların sırası kritiktir. Şimdi hangi sipariş doğrudur, onu nasıl sorgulayacağınıza bağlıdır. Bir indeks tam bir arama veya menzil taraması yapmak için kullanılabilir. Tam arama, dizindeki tüm sütunların değerlerinin belirtildiği ve sorgunun tam olarak satıra geldiği zamandır. Aramalar için sütunların sırası önemsizdir. Aralık taraması yalnızca bazı sütunların belirtildiği ve bu durumda siparişin önemli olduğu zamandır. SQL Server, yalnızca en soldaki sütun belirtildiyse ve ardından yalnızca en soldaki sonraki sütun belirtildiyse aralık taraması için bir dizin kullanabilir. Eğer (A, B, C) bir dizin varsa onun için aralık tarama için kullanılabilir A=@aiçin, A=@a AND B=@bama değil için B=@biçin, C=@cne de B=@b AND C=@c. Durumda A=@a AND C=@colduğu gibi, karma biridirA=@abölümü dizini kullanır, ancak kullanmaz C=@c(sorgu tüm B değerlerini tarar A=@a, 'atlamaz' C=@c). Diğer veritabanı sistemleri, dış sütunlar belirtilmediğinde bir dizindeki iç sütunlardan bir miktar faydalanabilecek 'atla tarama' işlecine sahiptir.

Elimizdeki bu bilgi ile indeks tanımlarına tekrar bakabilirsiniz. Tarihinde bir dizin (MostSelective, SecondMost, Least)yalnızca MostSelectivesütun belirtildiğinde etkili olur . Ancak en seçici olan bu, iç sütunların alaka düzeyi hızla azalacaktır. Çoğu zaman daha iyi bir dizinin açık (MostSelective) include (SecondMost, Least)veya açık olduğunu görürsünüz (MostSelective, SecondMost) include (Least). İç sütunlar daha az alakalı olduğundan, düşük seçicilik sütunlarını dizinde bu gibi doğru konumlara yerleştirmek, onları arama için gürültüden başka bir şey yapmaz, bu nedenle onları ara sayfaların dışına taşımak ve yalnızca yaprak sayfalarında tutmak mantıklıdır. sorgulanabilirlik amaçları. Başka bir deyişle, onları DAHİL ET'e taşıyın. LeastSütun boyutu arttıkça bu daha önemli hale gelir . Buradaki fikir, bu dizinin yalnızca belirtilen sorgulardan yararlanabilmesidirMostSelective ya tam bir değer ya da aralık olarak, ve bu sütun en seçici olanı zaten aday satırlarını büyük ölçüde kısıtlar.

Öte yandan bir endeks (Least, SecondMost, MostSelective)bir hata gibi görünebilir, ama aslında oldukça güçlü bir endeks. En Leastdıştaki sorgusu olarak sütuna sahip olduğu için, sonuçları düşük seçicilik sütunlarında toplamak zorunda olan sorgular için kullanılabilir. Bu tür sorgular OLAP ve analiz veri depolarında yaygındır ve tam da bu tür dizinlerin kendileri için çok iyi bir durum olduğu yerdir. Bu tür dizinler aslında tam olarak ilgili satırların büyük parçaları ( genellikle bir tür kategori veya türü gösteren aynı değer) üzerinde fiziksel düzeni düzenledikleri ve analiz sorgularını kolaylaştırdıkları için mükemmel kümelenmiş dizinler oluştururlar Least.

Maalesef, 'doğru' bir düzen yoktur. Herhangi bir çerez kesici tarifini takip etmemelisiniz, bunun yerine bu tablolarda kullanacağınız sorgu desenini analiz etmeli ve hangi dizin sütunu sırasının doğru olduğuna karar vermelisiniz.


3
Her zamanki gibi harika yanıt Remus. Üçüncü paragrafınızı birkaç kez daha okuyacağım ve takip edeceğim. Bunun tam olarak yapmam gereken şey olduğundan şüpheleniyorum.
Abe Miessler

"SQL Server, yalnızca en soldaki sütun belirtildiyse ve ardından yalnızca en soldaki sonraki sütun belirtildiyse aralık taraması için bir dizin kullanabilir." Anladığım kadarıyla eksik olan şey bu, teşekkürler! Aralık taramalarının yalnızca en sağdaki dizin sütununda yapılabileceğini bilmiyordum, ama şimdi yaptığım çok mantıklı.
Allon Güralnek

Bu açıklama Oracle DB için geçerli midir?
başka bir

1
@Roizpi Evet, temelde Indexes ile herhangi bir ilişki veritabanı aynı veya çok benzer şekilde çalışıyor.
Tatranskymedved

45

Remus'un dediği gibi iş yükünüze bağlıdır.

Yine de kabul edilen cevabın yanıltıcı bir yönünü ele almak istiyorum.

Dizindeki tüm sütunlarda eşitlik araması yapan sorgular için önemli bir fark yoktur.

Aşağıdaki iki tablo oluşturur ve bunları aynı verilerle doldurur. Tek fark, anahtarların en çokdan en az seçiciye, diğerinin tersine doğru sıralanmasıdır.

CREATE TABLE Table1(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);
CREATE TABLE Table2(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);

CREATE NONCLUSTERED INDEX MyINDX on Table1(MostSelective,SecondMost,Least);
CREATE NONCLUSTERED INDEX MyINDX2 on Table2(Least,SecondMost,MostSelective);

INSERT INTO Table1 (MostSelective, SecondMost, Least)
output inserted.* into Table2
SELECT TOP 26 REPLICATE(CHAR(number + 65),800), number/5, '~'
FROM master..spt_values
WHERE type = 'P' AND number >= 0
ORDER BY number;

Şimdi her iki tabloya karşı bir sorgu yapıyor ...

SELECT *
FROM   Table1
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~';

SELECT *
FROM   Table2
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~'; 

... Her ikisi de bir endeks cezası kullanır ve her ikisine de aynı maliyet verilir.

resim açıklamasını buraya girin

Kabul edilen cevaptaki ASCII sanatı aslında indekslerin nasıl yapılandırıldığı değildir. Tablo1 için dizin sayfaları aşağıda gösterilmiştir (tam boyutta açmak için resme tıklayın).

resim açıklamasını buraya girin

Dizin sayfaları, tüm anahtarı içeren satırları içerir (bu durumda, dizin benzersiz olarak bildirilmediğinden, ancak bu konu hakkında daha fazla bilgi göz ardı edilebildiğinden satır tanımlayıcı için ek bir anahtar sütun eklenir ).

Yukarıdaki sorgu için SQL Server sütunların seçiciliği umurumda değil. Kök sayfanın ikili bir aramasını yapar ve Anahtarın (PPP...,3,~ ) olduğunu >=(JJJ...,1,~ )ve < (SSS...,3,~ )bu yüzden de sayfayı okuması gerektiğini keşfeder 1:118. Daha sonra, o sayfadaki anahtar girişleri ikili olarak arar ve aşağıya gidilecek yaprak sayfasını bulur.

Dizini seçicilik sırasına göre değiştirmek, ikili aramadan beklenen anahtar karşılaştırma sayısını veya dizin araması yapmak için yönlendirilmesi gereken sayfa sayısını etkilemez. En iyisi olabilir marjinal anahtar karşılaştırma kendisi hızlandırmak.

Bazen en seçici dizini sipariş etmek, iş yükünüzdeki diğer sorgular için anlamlı olur.

Örneğin, iş yükü aşağıdaki formların her ikisinin de sorgularını içeriyorsa.

SELECT * ... WHERE  MostSelective = 'P'

SELECT * ...WHERE Least = '~'

Yukarıdaki dizinler hiçbirini kapsamaz. MostSelectivedeğerli bir arama ve arama ile bir plan yapmak için yeterince seçicidir, ancak karşı sorgu Leastdeğildir.

Ancak bu senaryo (bir bileşik dizinin önde gelen sütun (lar) ının alt kümesinde kapsayıcı olmayan dizin araması), bir dizin tarafından yardımcı olabilecek olası bir sorgu sınıfıdır. Asla MostSelectivekendi başına ya da MostSelective, SecondMosther üç sütunun bir kombinasyonuyla arama yapmazsanız ve bu teori avantajı sizin için işe yaramazsa.

Tersine sorgular gibi

SELECT MostSelective,
       SecondMost,
       Least
FROM   Table2
WHERE  Least = '~'
ORDER  BY SecondMost,
          MostSelective 

Sıkça reçete edilenin ters sırasına sahip olmak yardımcı olacaktır - sorguyu kapsadığı için, bir aramayı destekleyebilir ve satırları önyükleme için istenen sırada döndürür.

Bu tavsiye bir sıklıkla tekrarlanan parçasıdır ama en azından potansiyel yararı hakkında bir sezgisel var Yani diğer sorguları - ve aslında bakarak yerine geçmez senin iş yükü.


31

en seçici olacak sütunları dizin bildiriminin başına koymalısınız.

Doğru. Dizinler - birden çok sütundan oluşan kompozitler olabilir ve en soldaki prensip nedeniyle sıralama önemlidir. Bunun nedeni, veritabanının listeyi soldan sağa doğru kontrol etmesi ve tanımlanan sıra ile eşleşen karşılık gelen bir sütun başvurusu bulması gerektiğidir. Örneğin, adres tablosunda sütunları içeren bir dizine sahip olmak:

  • Adres
  • Kent
  • Durum

addressSütunu kullanan herhangi bir sorgu dizini kullanabilir, ancak sorgunun yalnızca cityve / veya statereferansları varsa - dizin kullanılamaz. Bunun nedeni, en soldaki sütuna başvurulmamasıdır. Sorgu performansı, hangisinin en uygun olduğunu söylemelidir - tek tek dizinler veya farklı siparişlere sahip birden çok kompozit. İyi okuma: Devrilme Noktası , Kimberley Tripp


Ya kullanılmayan en sağdaki sütun olsaydı? Yani bir sorgu Adres ve şehir kullanılan, ancak devlet DEĞİL. Dizin o zaman kullanılır mı?
Abe Miessler

@Abe: En sağda kullanılmaz - soldan başlayarak dizin sırasını sağlamanız gerekir. Bayan, kullanamazsýn.
OMG Ponies

4
@Abe: Adres ve şehri sorguladınız, ancak EĞER DEĞİLSİNİZ - o zaman evet, dizin kullanılır. Başka bir deyişle, veritabanı, bir dizinin solundan başlayıp sorgulanan alanları kullanarak sağa hareket edebildiği sürece, bir isteği karşılamak için kısmi dizinler kullanabilir. Bununla birlikte, Adres ve Durum'u kullanarak, ancak şehir DEĞİL kullanarak sorguladıysanız, dizini kullanmaya devam edebilir, ancak bu kadar verimli olmayacaktır - çünkü artık dizinin Adres bölümünü kullanabilmektedir (b / c sonraki şehir ve sorguda kullanılmıyor).
JaredC

6

Diğer tüm cevaplar yanlış.

Bileşik bir dizindeki her bir sütunun seçiciliği , sipariş seçilirken önemli değildir .

İşte basit düşünce süreci: Etkili bir şekilde, bir dizin ilgili sütunların birleşmesidir.

Bu mantığı verirsek, tek fark, daha önce ve daha sonra dizede farklılık gösteren iki 'dizeyi' karşılaştırmaktır. Bu, toplam maliyetin küçük bir parçasıdır. Bir Yanıtta belirtildiği gibi "ilk geçiş / ikinci geçiş" yoktur.

Peki hangi düzen kullanılmalıdır?

  1. İle test kolonu (ler) i ile başlayın =olarak, herhangi bir sırayla.
  2. Sonra bir aralık sütun yapıştırın.

Örneğin, çok düşük seçicilik sütunu burada birinci olmalıdır :

WHERE deleted = 0  AND  the_datetime > NOW() - INTERVAL 7 DAY
INDEX(deleted, the_datetime)

Dizindeki siparişi değiştirmek, tamamen yok saymanızı sağlar deleted.

(Sütunları sipariş etmek için çok daha fazla kural var.)


Olumsuz oy yanlış olduğum için mi? Yoksa güçlü bir fikrim olduğu için mi? Veya başka bir şey?
Rick James

benim downvote değil, ama silinmiş = 0 bana düşük seçicilik değil gibi geliyor? Tablodaki satırların çoğunluğu olacağını hayal ediyorum.
Greg

@Greg - Bunun "düşük seçicilik" anlamına geldiğini düşünüyorum - Yani, deletedistenmeyen satırları filtrelemede çok yardımcı olmaz. Daha iyi bir örnek var mı? (Cevabı yazdığımda aklıma gelen bu oldu.)
Rick James

Benim açımdan yanlış anlama.
Greg

1
@ClickOk - Teşekkürler. Yemek kitabım
Rick James
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.