Anasayfa / Yazılım / SQL / Non-Clustered Index Nedir?

Non-Clustered Index Nedir?

SQL’de verilerimizi saklarken her tabloda indeksleme yapısına gideriz. Indeksleme aslında iki türlüdür. Birisi clustered index diğeri non-clustered indekstir. Clustered index aslında hepimizin bildiği bir tablo içinde birbirinin aynı olmayan verileri sağlamak üzere kullanmış olduğumuz genellikle tabloda ilgili alan için (ilgili tabloya özel) durum için belli bir ID etiketi ile tanımladığımız fiziksel indekslemedir. Örneğin Müşteriler tablosundaki MusteriID, Öğrenciler tablosundaki OgrenciID gibi. Bunu çok sık kullanırız. Ve bu Clustered index her tabloda en fazla 1 tane olabilir. Non-Clustered ise daha farklı bir yapıdır. Buradaki amaç verilerin fiziksel olarak sıralaması değil, verilerin tutulduğu yerlerin adreslerini işeretçi niteliğinde tutmaktır. Bu konuda bir kaç gün önceki yazımı da okuyabilirsiniz.

Index nedir, ne işe yarar?

Non-Clustered index bir tabloda 999 adet olabilir. Tabi bu kadar abartmamak gerek 🙂 Şimdi bu non-clustered indekx nasıl oluşturulur, avantajları nedir, ne değildir bu yazıda benim anlatmak istediğim aslında bu. Bir tablo üzerinde her bir kolon için non-clustered index tanımlanmamalıdır. Ancak bazı spesifik durumlarda, örneğin bir telefon rehberinde kişi bilgileri içinde Ad ve Soyad alanı için non-clustered index yer alabilir. Bu arama performansının artmasına neden olacaktır.

Örnek olarak AdventureWorks veritabanı üzerindeki tablolarda non-clustered uygulanmış bir tabloya göz atalım.

271201

Burada sarı ile belirttiklerim non-clustered indeksler, kırmızı ise clustered indeks. Görüntülediğimiz de IX_Person_LastName_FirstName_MiddleName üzerinde çift tıklayalım. Karşımıza bu indexin özelliklerinin gösterildiği bir pencere çıkar. Burada LastName, FirstName ve MiddleName alanlarının non-clustered yapıldığını görüyorsunuz.

271202

Şimdi indekslemenin önemini bir takım sorgular ile görelim. Bunu görebilmek için yürütme planı dediğimiz execute plans alanını kullanacağım. Burada bir sorgunun nasıl yürütüldüğünü görebilir aynı zamanda performans kıyaslaması yapabiliriz.

Query penceremiz açıkken üstteki barda yer alan Include Actual Execution Plan butonuna tıklayınız.

271203

Bu butona tıkladığınız da buton seçili hale gelir, herhangi bir pencere açılmaz. Seçili hale geldiğini görebiliriz.

271204

Şimdi bir AdventureWorks veri tabanı üzerinde çalıştığımıza emin olduktan sonra aşağıdaki sorguları çalıştıralım.

SELECT LastName, FirstName FROM Person.Person 
WHERE LastName = 'Smith';
SELECT LastName, FirstName FROM Person.Person 
WHERE FirstName = 'Ken';
SELECT ModifiedDate FROM Person.Person 
WHERE ModifiedDate BETWEEN '2005-01-01' and '2005-01-31';

Üç sorguyu da birlikte çalıştırın ve sonuçların gösterildiği alanda Execution Plan sekmesine geçiniz. Burada 3 sorgu için execution plan görülmektedir.

271205

Şimdi burada dikkatinizi çekmek istediğim nokta resimde de görüleceği üzere sarı bantlı kısımlar. Burada yer alan Query Cost değerlerine her 3 sporgu için bakınız. İlkinde %0, ikincisinde %3 ve üçüncüsünde bu değer %96.

Query 1 yani ilk satırda yer alan sorgumuzun sonucu %0. Peki neden bu yüzde sıfır, çünkü bizim Person.Person tablomuzda LastName alanı indekslenmiştir, yani non-clustered yapılmıştır. Üstte ki resimde daha önce görmüştük, önce LastName sonra FirstName ve daha sonra MiddleName idi. LastName alanı ilk sırada yer aldığı için sorgumuzun sonucunda SQL Server performansını en iyi şekilde kullanıyor ve verileri en hızlı şekilde getiriyor. Şöyle düşünün bir telefon rehberi kurcalıyorsunuz ve aradığınız kişinin soyadını biliyorsunuz, dolayısı ile her kayda her sayfaya bakmadan sadece ilgili soyadının bulunacağı sayfaya yönlenir ve orada arama yaparsınız. Yani diğer veriler üzerinde tarama yapmadan hedefe yönelik olarak daha az veri üzerinde arama gerçekleştirirsiniz. Bu birinci sorguda da Smith soyadı bu şekilde aranıyor.

İkinci sorgu %3. FirstName alanı da Non-Clustered olarak tanımlanmış durumda ancak bu sefer ikinci sırada. Ne yapılıyor her sayfadaki adı Ken olan telefon rehberindeki verileir listelediğinizi düşünün. Bu sefer isme göre bir arama gerçekleşiyor.

Son sorgumuzda ise non-clustered tanımlanmamış ve clustered olmayan bir kolon üzerinde yani modifieddate üzerinde bir arama yapılıyor ve burada aldığımız sonuç ise %96. Çünkü SQL server burada tüm verileri tüm satırları değerlendiriyor ve daha sonra listeleme yapıyor. Yani her bir clustered indexe sahip veri değerlendiriliyor.

Bu arada bu 3 sorgu bazında değerleri baz alıyoruz, yani %100’lük performansın %96’ya yakını 3. sorgu üzerinde, %3’e yakın kısmı 2. sorgu üzerinde, %0’a yakın kısmı 1. sorgu üzerinde harcandı. Yuvarlama yapılarak SQL değerleri hesaplamaktadır, yüzde bilgisini buna göre verir.

Aşağıdaki sorguları karşılaştırıyorum.

SELECT LastName FROM Person.Person 
WHERE LastName = 'Smith';
SELECT LastName FROM Person.Person
WHERE LastName LIKE 'Sm%';

271206

Bakın bu sefr 1. sorgu %50, 2. sorguda %50 değerine sahip. Yani tüm performansı her iki sorgu eşit derecede kullanmış. Dolayısı ile her iki sorguda aynı performansta. Peki neden aynı? Açıklayalım. İlk sorguda Smith adını direkt verdik, dolayısı ile soyada göre listeleme yaptığımız için S harfi ile başlayan veri kümesinde arama yapıldı. Direkt olarak oraya gidip sadece Smith verileri listelendi. İkincisinde de Sm harfleri verildiği için yine aynı küme üzerinde işlem yapıldı çünkü bu tablodaki veriler içinde Sm ve Smith ile arama yapıldığında dönen sonuçlar içinde sadece 2 fark var.

Aşağıdaki sorguları çalıştırıp sonuçları görüyoruz.

SELECT LastName FROM Person.Person 
WHERE LastName LIKE 'Sm%';
SELECT LastName FROM Person.Person 
WHERE LastName LIKE '%mith';

271207

Bu sorgularımızda görüldüğü üzere tüm performansın %3’ü 1. sorguda, %97’si 2. sorguda harcandı. Bunun sebebi şu, ilk sorguda LastName alanında sadece sm ile başlayan veriler aranırken ikinci sorguda ilk harfler yani mith önündeki harfler, değerler ne olursa olsun ara gibi bir sorgu mevcut, dolayısı ile tablodaki tüm veriler tek tek değerlendirilir ve hepsi taranır.

Aşağıdaki sorguları yazıp çalıştıralım.

SELECT LastName FROM Person.Person 
WHERE LastName LIKE '%mith';
SELECT ModifiedDate FROM Person.Person 
WHERE ModifiedDate 
BETWEEN '2005-01-01' and '2005-01-31';

271208

Bu sorgularımızda görüldüğü üzere tüm performansın %3’ü 1. sorguda, %97’si 2. sorguda harcandı. Bunun sebebi şu, ilk sorguda ilk harfler yani mith önündeki harfler, değerler ne olursa olsun ara gibi bir sorgu mevcut, ikinci sorguda ise ModifiedDate alanına göre yani non-clustered edilmemiş bir alana göre sorgulama mevcut. Dolayısı ile bu iki sorgu arasında en performanslı olan ilki oluyor.

Indeksleme SQL’de performansı arttıran bir durumdur. Dolayısı ile başvurulması gerekir ancak her tabloda her kolonun indekslenmesi de aynı zamanda performans açısından zorluklar yaratmaktadır. Dolayısı ile veritabanı tasarlarken bu durumları göz önüne almalıyız ve gerektiği noktalarda, örnepğin ad soyad, ürün adı, ünvan vb listelenebilecek alanlarda indekslemeye başvurup gerekmediği noktalarda da kullanmamalıyız.

Bir sonraki yazımda bir tablo oluşturduktan sonra bu tablodaki kolonları nasıl indeksleriz göstermek istiyorum. Şimdilik bu kadar..

5 yorum

  1. Teşekkürler, gerekli bilgiyi edindim 🙂

  2. Teşekkürler 🙂

  3. Sayın üstat, değerli vaktinizden bir dakika ayırabilirseniz size müteşekkir olacağım.
    Üstadım, tarih ve vakit bilgileri için özel olarak bir indexleme komutu vermek gerekir mi?
    Sıkı sıkıya tarih ve vakit bilgileri ile işlem yaptığımızda bunların indexleme önceliğini belirleyebiliyor muyuz ?
    Hürmetlerimi arz ederim.

  4. Çok teşekkürler, mükemmel bir anlatım olmuş

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir