Kümelenmiş ve Kümelenmemiş Dizin arasındaki performans farkı


22

Ben okuyordum Clusteredve Non Clustered Indexes.

Clustered Index- Veri Sayfaları içeriyor. Bu, tam satır bilgisinin Kümelenmiş Dizin Sütununda bulunacağı anlamına gelir.

Non Clustered Index- Yalnızca Kümelenmiş Dizin sütunu (varsa) veya bir Sayfadaki Dosya Girinti + Sayfa Numarası + Toplam Satırlar biçimindeki Satır Bulucu bilgilerini içerir. Bu, sorgu motorunun gerçek verileri bulmak için ek bir adım atması gerektiği anlamına gelir.

Sorgu - biz tablo sadece biri olabileceğini bildiği gibi ben pratik bir örnek bir yardımı ile performans farkını nasıl öğrenebilirim Clustered Indexve sağlar sortingde Clustered Index Columnve Non Clustered Indexvermeyen sortingve 999 destekleyebilir Non Clustered Indexesiçinde SQL Server 2008ve 249 SQL Server 2005.


2
Ne yaptığınız zamanki performans farkı ?, bu masaya ne tür işler yapmak istersiniz ?, her ihtiyaca uygun tek bir çözüm yoktur
Lamak

2
Belki burada somut bir tartışma. stackoverflow.com/questions/91688/… stackoverflow.com/questions/5070529/… stackoverflow.com/questions/1251636/… Kümelenmiş ve kümelenmemiş dizinler arasındaki farklar hakkında bir tez yazabiliriz, ancak şunu düşünmüyoruz. okumanız için zaten orada olmayan bir şey söyleyebilirim.
Aaron Bertrand

4
Siz yazdınız: "Bu, sorgu motorunun gerçek verileri bulmak için ek bir adım atması gerektiği anlamına gelir." Aslında, ihtiyacınız olan tek şey dizinde yer alan sütunlarsa , hedef satırlarınızı kümelenmemiş dizinde bulduktan sonra herhangi bir ek adım atmanız gerekmez . Yalnızca kümelenmemiş dizin tarafından kaplanmayan sütunlara ihtiyacınız olduğunda, SQL Server'ın bir yer imi araması yapması gerekir .
Nick Chammas

Yanıtlar:


43

Çok önemli bir soru olduğu için bu çok güzel bir soru. Bu çok büyük bir konudur ve size göstereceğim şey basitleştiricidir, böylece temel kavramları anlayabilirsiniz.

Öncelikle kümelenmiş indeksi gördüğünüzde tabloyu düşünün . Bir tablo kümelenmiş bir dizin içermiyorsa SQL sunucusunda bir öbektir. Masada kümelenmiş bir dizin oluşturmak aslında masayı b-ağacı tipi bir yapıya dönüştürür. Kümelenmiş dizininiz tablonuzdur tablodan ayrı değildir

Neden yalnızca bir kümelenmiş dizine sahip olabileceğinizi merak ettiniz mi? İki kümelenmiş indeksimiz olsaydı, tablonun iki kopyasına ihtiyacımız olurdu. Sonuçta verileri içerir.

Bunu basit bir örnek kullanarak açıklamaya çalışacağım.

NOT: Bu örnekte tabloyu oluşturdum ve 3 milyondan fazla rastgele girdiyle doldurdum. Ardından asıl sorguları yürüttü ve yürütme planlarını buraya yapıştırın.

Gerçekten kavramanız gereken şey, O gösterimi veya operasyonel verimliliktir . Aşağıdaki tabloya sahip olduğunuzu varsayalım.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

İşte burada MüşteriNo kümelenmiş bir anahtarla temel bir tablomuz var (Birincil anahtar varsayılan olarak kümelenmiştir). Böylece tablo, birincil müşteri koduna göre düzenlenir / sıralanır. Orta seviyeler MüşteriNo değerleri içerecektir. Veri sayfaları tüm satırı içerecek, böylece tablo satırı olacaktır.

Ayrıca, MüşteriAdı alanında kümelenmemiş bir dizin de oluşturacağız. Aşağıdaki kod yapacak.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Dolayısıyla bu endekste veri sayfaları / yaprak seviyesi düğümlerinde kümelenmiş endekste ara seviyelere bir gösterici bulacaksınız. Dizin, MüşteriAdı alanı çevresinde düzenlenir / sıralanır. Böylece orta seviye MüşteriAdı değerlerini içerir ve yaprak seviyesi imleci içerecektir (bu işaretçi değerleri aslında birincil anahtar değerlerdir veya MüşteriNo sütunu).

Doğru, eğer aşağıdaki sorguyu uygularsak:

SELECT * FROM Customer WHERE CustomerID = 1 

SQL muhtemelen kümelenmiş bir dizini bir arama işlemi aracılığıyla okuyacaktır. Arama işlemi, sıralı bir arama olan bir taramadan çok daha verimli olan ikili bir aramadır. Bu yüzden yukarıdaki örneğimizde dizin okunur ve ikili bir arama kullanarak SQL, aradığımız kriterlere uymayan verileri elimine eder. Sorgu planı için ekli ekran görüntüsüne bakın.

görüntü tanımını buraya girin

Dolayısıyla, operasyonların sayısı veya arama işlemi için O Notasyonu aşağıdaki gibidir:

  1. Aranan değeri ara düzeydeki değerlerle karşılaştırarak, kümelenmiş dizinde ikili arama yapın.
  2. Eşleşen değerleri döndür (kümelenmiş dizinin içindeki tüm verileri içerdiğinden, satırdaki tüm dizinlerden gelen tüm sütunları geri getirebileceğini unutmayın)

Bu yüzden iki işlem. Ancak aşağıdaki sorguyu uyguladıysak:

SELECT * FROM Customer WHERE CustomerName ='John'

SQL şimdi arama yapmak için MüşteriAdı üzerindeki kümelenmemiş dizini kullanacak. Ancak, bu kümelenmemiş bir dizin olduğundan, satırdaki verilerin tümünü içermez.

Bu nedenle SQL, eşleştirilen kayıtları bulmak için ara seviyelerde arama yapacaktır, ardından gerçek verileri almak için kümelenmiş indeks üzerinde başka bir arama yapmak için geri döndürülen değerleri kullanarak arama yapacaktır. Bu kafa karıştırıcı sesler biliyorum ama okudum ve hepsi netleşecek.

Kümelenmemiş dizinimiz yalnızca MüşteriAdı alanını (ara düğümlerde depolanan dizinli alan değerleri) ve Müşteri Kimliği olan verinin göstergesini içerdiğinden, endeksin Müşteri Soyadı kaydı yoktur. Müşteri Soyadı kümelenmiş dizin veya tablodan alınmalıdır.

Bu sorguyu çalıştırırken aşağıdaki yürütme planını alıyorum:

görüntü tanımını buraya girin

Yukarıdaki ekran görüntüsünde dikkat etmeniz gereken iki önemli nokta var.

  1. SQL eksik bir dizine sahip olduğumu söylüyor (yeşil metin). SQL, CustomerName üzerinde CustomerID ve CustomerSurname içeren bir dizin oluşturmamı öneriyor.
  2. Ayrıca, sorgu zamanının% 99'unun birincil anahtar dizini / kümelenmiş dizinde bir anahtar araması yapmak için harcandığını da göreceksiniz.

SQL neden bu adı MüşteriName'de öneriyor? Endeks yalnızca MüşteriNo içerdiğinden ve MüşteriName SQL hala tablo / kümelenmiş endekslerden Müşteri soyadını bulmak zorunda.

Dizini yarattığımızda ve CustomerSurname sütununu dizine eklersek, SQL yalnızca kümelenmemiş dizini okuyarak tüm sorguyu karşılayabilir. Bu yüzden SQL kümelenmemiş dizinimi değiştirmemi öneriyor.

Burada, kümelenmiş anahtardan CustomerSurname sütununu almak için SQL'in yapması gereken ekstra işlemi görebilirsiniz.

Böylece işlem sayısı aşağıdaki gibidir:

  1. Aranan değeri ara düzeydeki değerlerle karşılaştırarak, kümelenmemiş dizinde ikili arama yapın
  2. Eşleşen düğümler için kümelenmiş dizindeki veriler için işaretçiyi içerecek yaprak düzeyi düğümünü okuyun (yaprak düzeyi düğümleri bu arada birincil anahtar değerlerini içerecektir).
  3. Dönen her değer için, burada satır değerlerini almak için kümelenmiş dizinde (tablo) bir okuma yapın, Müşteri Soyadını okurduk.
  4. Eşleşen satırları döndür

Bu değerleri çıkarmak için 4 işlemdir. Kümelenmiş dizini okumakla karşılaştırıldığında gereken işlemlerin iki katı. Kümelenmiş dizininizin tüm verileri içerdiği için en güçlü dizininiz olduğunu gösterin.

Bu yüzden sadece son bir noktayı netleştirmek için. Neden kümelenmemiş dizindeki işaretçinin birincil anahtar değeri olduğunu söylüyorum? Kümelenmemiş dizinin yaprak düzeyi düğümlerinin, sorgumu değiştirdiğim birincil anahtar değerini içerdiğini göstermek için:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

Bu sorguda SQL, Müşteri Kimliği'ni kümelenmemiş dizinden okuyabilir. Kümelenmiş dizinde bir arama yapmak gerekmez. Bu, buna benzeyen yürütme planında görebilirsiniz.

görüntü tanımını buraya girin

Bu sorgu ve önceki sorgu arasındaki fark dikkat edin. Arama yok. SQL, kümelenmemiş dizindeki tüm verileri bulabilir

Umarım kümelenmiş dizinin tablo olduğunu ve kümelenmemiş dizinlerin tüm verileri içermediğini anlamaya başlayabilirsiniz. Dizin oluşturma, ikili aramaların yapılabilmesi nedeniyle seçimleri hızlandıracaktır, ancak yalnızca kümelenmiş dizinler tüm verileri içermektedir. Bu nedenle, kümelenmemiş bir dizinde bir arama neredeyse her zaman kümelenmiş dizinden değerlerin yüklenmesine neden olur. Bu ekstra işlemler, kümelenmemiş dizinleri kümelenmiş bir dizinden daha az verimli hale getirir.

Umarım bu işleri temizler. Bir şey anlam ifade etmiyorsa, lütfen bir yorum gönderin; açıklığa kavuşturmaya çalışacağım. Burada oldukça geç ve beynim biraz düz hissediyor. Kırmızı boğa zamanı.


Bir sorum var. NEDEN bu sorgu için MüşteriName'deki kümelenmemiş endekste bir endeksin aradığı arama SELECT * FRER Müşteri NEREDE MüşteriAdı = 'John'. Kümelenmemiş bir dizin olduğundan, özel ad sıralanmayacaktır. Bu yüzden bir dizin taraması yapılmamalıdır.
ckv

Btw Büyük cevap tamamen yukarıdaki soru dışında anladım.
ckv

1
Verilerin sırasına göre bir dizin sıralanır. Örneğin, endekslenmiş değer olduğundan Müşteri adına göre sıralanır. Yani sıralanır. Hala yaprak seviyesini veya sayfaları taraması gerektiğini unutmayın.
Namphibian

9

"Bu, sorgu motorunun gerçek verileri bulmak için ek bir adım atması gerektiği anlamına gelir."

Zorunlu değil - eğer dizin verilen bir sorguyu kapsıyorsa, veri sayfalarına bir gezi yapılması gerekmez. Ayrıca, içerilen sütunlarla, kümelenmemiş bir dizine, anahtar boyutunu değiştirmeden kaplamasını sağlamak için ek sütunlar eklenebilir.

Bu yüzden nihai cevap - Bağlıdır (tek bir soruda gerçekten ele alabileceğinden çok daha fazla bilgiye dayanarak) - endekslerin tüm yeteneklerini anlamanız gerekir ve verilen bir sorgu için uygulama planı beklentilerinizden farklı olabilir.

Elimdeki genel kural, bir tablonun her zaman kümelenmiş bir dizine sahip olmasıdır (ve genellikle bir kimlik veya sıralı bir GUID'de), ancak kümelenmemiş dizinler performans için eklenir. Ancak her zaman istisnalar vardır - yığın tablolarının bir yeri vardır, daha geniş kümelenmiş dizinlerin bir yeri vardır. Sayfa başına daha fazla satıra sığması daha dar olan görünüşte fazla olan dizinlerin yeri vardır. vesaire vesaire.

Ve izin verilen çeşitli endekslerdeki sınırlar konusunda endişelenmem - bu kesinlikle gerçek dünyadaki pek çok örnekte devreye girmeyecek.


2
+1 için there are always exceptions- çok fazla insan bunu ihmal ediyor ve kümelenmiş her dizinin ne olduğu int identityönemli değil.
JNK,
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.