SQL Server Indexing Deep Dive: Clustered, Non-Clustered ve Covering Indexler
SQL Server'da performansın belki de en kritik bileşeni index'lerdir. İyi tasarlanmış bir index, sorgu süresini saniyelerden milisaniyelere indirebilirken, yanlış veya eksik index, tüm veritabanı sunucusunu çökerten bir performans kabusuna dönüşebilir. Bu yazıda, SQL Server'daki index mimarisini, clustered ve non-clustered index'ler arasındaki temel farkları, covering index ile sorgu performansını nasıl optimize edeceğinizi ve index bakım stratejilerini derinlemesine inceleyeceğiz.
1. Index Mimarisi: B-Tree Yapısı
SQL Server'daki tüm rowstore index'ler (clustered ve non-clustered), temel olarak bir B-tree (B+-tree) yapısı üzerine inşa edilmiştir. Bu hiyerarşik yapı, verilere hızlı erişim sağlamak için tasarlanmıştır.
-
Kök Düzeyi (Root Level): Index'in en üst seviyesidir. Arama işlemi buradan başlar.
-
Ara Düzeyler (Intermediate Levels): Kök ile yaprak düzeyi arasındaki yönlendirme düğümleridir. Her düzey, bir sonraki alt düzeye işaret eden anahtar değerleri içerir.
-
Yaprak Düzeyi (Leaf Level): Index'in en alt seviyesidir ve asıl veriye veya verinin yerini gösteren işaretçiye (pointer) erişimi sağlar.
2. Clustered Index (Kümelenmiş İndeks)
Clustered index, bir tablodaki veri satırlarının fiziksel olarak sıralanma ve saklanma düzenini belirler. Bir başka deyişle, clustered index'in yaprak düzeyi, tablonun veri sayfalarının (data pages) kendisidir. Bu nedenle, bir tabloda yalnızca tek bir clustered index olabilir.
Temel Özellikler:
-
Veri Düzeni: Tablodaki veriler, clustered index anahtar sütununa göre fiziksel olarak sıralıdır.
-
Birincil Anahtar (Primary Key): Varsayılan olarak, bir tabloya Primary Key oluşturduğunuzda, SQL Server üzerinde otomatik olarak bir clustered index oluşturur.
-
Her Zaman Kapsar (Covering): Clustered index, tablodaki tüm sütunları içerdiği için her zaman bir "covering index"tir. Ancak, "covering index" terimi genellikle non-clustered index'ler bağlamında kullanılır.
Ne Zaman Kullanmalı?
-
Sorgularda sıklıkla aranan veya sıralama (ORDER BY) yapılan sütunlarda.
-
Aralık (range) sorgularının (BETWEEN, >, <) yoğun olduğu durumlarda.
-
Tablonun çoğu sorgusunda kullanılan birincil anahtar sütununda.
3. Non-Clustered Index (Kümelenmemiş İndeks)
Non-clustered index, tablodaki veri satırlarından fiziksel olarak ayrı bir yapıdadır. Index'in yaprak düzeyi, index anahtar sütunlarını ve satır bulucuyu (row locator) içerir.
-
Satır Bulucu (Row Locator):
-
Tablo bir Heap (clustered index'siz) ise, row locator, veri satırının fiziksel adresi olan RID (Row ID)'dir.
-
Tablo bir Clustered Table ise, row locator, ilgili satırın clustered index anahtar değeridir.
-
-
Key Lookup (Anahtar Arama): Non-clustered index, sorguda istenen tüm sütunları kapsamıyorsa, SQL Server önce index'teki row locator'ı bulur, ardından bu locator'ı kullanarak veri sayfasına gidip eksik sütunları alır. Bu işleme Key Lookup (veya Bookmark Lookup) denir ve performansı olumsuz etkileyebilir.
-
Birden Fazla Olabilir: Bir tabloda 999 adede kadar non-clustered index oluşturulabilir.
Ne Zaman Kullanmalı?
-
WHEREcümleciğinde sıklıkla kullanılan sütunlarda. -
JOINişlemlerinde kullanılan sütunlarda. -
Belirli bir sütunu hızlıca aramak gerektiğinde (ancak tüm sütunların getirilmesi gerekmediğinde).
4. Covering Index (Kapsayan İndeks)
Covering index, bir sorgunun ihtiyaç duyduğu tüm sütunları index'in yaprak düzeyinde barındıran bir non-clustered index'tir. Bu sayede SQL Server, veri sayfalarına (table veya clustered index) ek bir erişim (lookup) yapmak zorunda kalmaz; tüm veriyi doğrudan index'ten okur.
Nasıl Oluşturulur?
Covering index oluşturmanın iki yolu vardır:
-
Tüm Sütunları Anahtar Olarak Eklemek: Sorguda geçen tüm sütunları
CREATE INDEXifadesinin anahtar sütun listesine eklemek. Ancak bu, index'in boyutunu ve güncelleme maliyetini gereksiz yere artırabilir. -
INCLUDEKullanımı (Önerilen): Sorguda geçen ancak arama (search) veya sıralama (sort) işlemlerinde kullanılmayan sütunlar,CREATE INDEXifadesindeINCLUDEanahtar kelimesi ile eklenir.
sql
-- Örnek: Bir sorguyu covering index ile kapsamak -- Sorgu: SELECT FirstName, LastName, Salary FROM Employees WHERE LastName = 'Smith'; CREATE NONCLUSTERED INDEX IX_Employees_LastName ON Employees (LastName) INCLUDE (FirstName, Salary);
Faydaları:
-
Key Lookup'u Ortadan Kaldırır: Sorgu, index'ten direkt olarak karşılanır, böylece gereksiz I/O işlemleri önlenir.
-
Performansı Artırır: Özellikle büyük tablolarda, covering index kullanımı sorgu sürelerini çarpıcı biçimde düşürebilir.
-
Daha Verimli I/O: Index sayfaları genellikle veri sayfalarından daha "ince" (daha az sütun içerdiği için) olduğundan, bir index scan işlemi bir table scan işleminden daha verimlidir.
5. Index Bakımı (Maintenance)
Zamanla, özellikle çok fazla INSERT, UPDATE ve DELETE işlemi gören tablolarda index'ler parçalanır (fragmentation) ve performans düşer. Düzenli index bakımı şarttır.
İki Temel Bakım Yöntemi:
-
Index Reorganize (Yeniden Düzenleme): Index'in yaprak düzeyindeki sayfaları fiziksel olarak yeniden düzenleyerek parçalanmayı azaltır. Bu işlem, index'i yeniden oluşturmaya göre daha az kaynak tüketir ve çevrimiçi (online) olarak yapılabilir. Genellikle düşük-orta düzey parçalanma (%5 - %30) için tercih edilir.
-
Index Rebuild (Yeniden Oluşturma): Index'in tamamını silip baştan oluşturur. Parçalanmayı tamamen ortadan kaldırır ve sayfa yoğunluğunu (page density) artırır. Bu işlem, reorganize'a göre daha fazla kaynak tüketir ve genellikle yüksek parçalanma (%30 ve üzeri) durumlarında tercih edilir.
Bakım Stratejisi İpuçları:
-
Parçalanmayı İzleyin:
sys.dm_db_index_physical_statssistem dinamik yönetim görünümünü (DMV) kullanarak index parçalanma oranlarını düzenli olarak kontrol edin. -
Otomasyon: Index bakım görevlerini SQL Server Agent job'ları ile otomatikleştirin.
-
Çevrimiçi İşlemler: Mümkünse, kullanıcı erişimini engellememek için
ONLINE = ONseçeneği ile rebuild işlemlerini gerçekleştirin (Enterprise Edition ve bazı standart sürümlerde desteklenir).
6. Performans İpuçları ve Kaçınılması Gerekenler
-
Az Sayıda, Doğru Index: Çok fazla index,
INSERT,UPDATEveDELETEişlemlerini yavaşlatır. Sadece ihtiyaç duyulan index'leri oluşturun. -
Sorguları Analiz Edin: Yavaş çalışan sorgular için execution plan'larını inceleyerek eksik veya yanlış index'leri tespit edin. Key Lookup işlemleri, covering index ihtiyacının en büyük göstergesidir.
-
Filtered Index (Filtreli İndeks): Belirli bir veri alt kümesi üzerinde sorgular yoğunsa,
WHEREkoşulu içeren bir filtered index oluşturmayı düşünün. Bu, index boyutunu ve bakım maliyetini azaltır. -
Sütun Seçimine Dikkat Edin: Index anahtarı olarak çok geniş (ör.
VARCHAR(MAX)) veya çok fazla sütun seçmekten kaçının.
Sonuç:
SQL Server index'leri, veritabanı performansının temel taşıdır. Clustered index, verinin fiziksel düzenini belirlerken; non-clustered index'ler, belirli sorguları hızlandırmak için kullanılır. Covering index ise, sorguları veri sayfalarına ek bir erişim yapmadan index'ten karşılayarak en büyük performans sıçramasını sağlayan tekniktir. Ancak, index'lerin bakımının ihmal edilmesi, zamanla kazanılan performansı geri alır. Düzenli parçalanma izleme ve reorganize/rebuild stratejileri ile index'lerinizi ilk günkü performansında tutabilirsiniz.