SQL 2005 ve muhtemelen SQL 2008 için, tablo dediğimiz yapılar nasıldır, mantıksal ve fiziksel olarak nasıl işlenir dersek...
Büyükten küçüğe doğru gidersek Tablo, Extent, Page olarak sıralamamızı yapabiliriz. Bu sıradan da anlaşılacağı gibi Page'ler ile Extent'ler oluşur. Extent'ler ile de tablo dediğimiz yapı oluşur.
SQL'de tabloların oluşabileceği 3 çeşit allocation unit vardır. Tablo bunlardan bir veya daha fazlası ile oluşturulabilir. Her tabloda mutlaka olan tek allocation unit IN_ROW_DATA'dır. Diğerleri ise LOB_DATA ve ROW_OVERFLOW_DATA'dır.
IN_ROW_DATA türü allocaion unitler; büyük olmayan veri tiplerini barındırır. Eğer varchar, nvarchar, varbinary, sql_variant veri tiplerinin toplam satır boyutu 8KB üzerinde çıkarsa, ROW_OVERFLOW_DATA kullanılmaya başlanır. Bu kısımların detaylarını Page'leri incelerken göreceğiz.
LOB_DATA türü allocation unit'ler; text, ntext, image, xml, varchar(max), nvarchar(max), varbinary(max) türlerini barındırır.
SQL'de Page boyutu 8KB'dir. Disk işlemleri Page üzerinden yapılır yani Page üzerinde okuma veya yazma işlemleri yapılır. Her Page 96 byte'lık bir header bilgisi ile başlar ve bu bilginin hemen ardından Data Row'lar gelir. Header içerisinde Page Number, Page Type, Page için kalan boş alan, ve Page'ın owner (Extent) bilgisi tutulur. Her bir Data Row'un, Page üzerindeki ilk Data Row'dan ne kadar sonra başladığı bilgisi Page'in en altındaki offset tablosunda tutulur. Bu tablodaki sıralama Data Row'ların Page içerisindeki sıralamasının tam tersidir.
Bir Data Row birden fazla Page içerisinde olamaz. Peki o zaman bizim 8K'dan büyük satır veya alanlarımız ne olacak derseniz. Büyük veri barındıran Data Row'lar farklı tür bir allocation unit içerisindeki Page'lerde saklanır. text, ntext, image, nvarchar(max), varchar(max), varbinary(max), ve xml veri tipleri LOB_DATA türünde, varchar, nvarchar, varbinary, sql_variant veri tiplerinden toplam içeriği 8KB üzerinde olanlar ROW_OVERFLOW_DATA türündeki allocation unit içerisindeki Page'lerde saklanır.
Normal şartlarda varchar, nvarchar, varbinary, sql_variant veri tiplerin tek başına uzunluğu 8K'yı geçemez ancak birlikte toplam uzunlukları bu değeri geçebilir. Bir INSERT veya UPDATE işlemi toplam row boyutunu (tüm kolonlar ile) 8K üzerine taşırsa, bu row ROW_OVERFLOW_DATA üzerindeki bir Page'e taşınır, bu taşımada en büyük olan kolon uzunluğuna göre bir yeni Page uzunluğu belirlenir. Taşınmadan önceki IN_ROW_DATA üzerindeki değeri de 24 byte'lık bir pointer ile güncellenir. Toplam row boyutu 8K altına düştüğünde ise, ilgili işlemler geri alınır ve row tekrar IN_ROW_DATA allocation unit üzerindeki Page' taşınır.
IN_ROW_DATA ve ROW_OVERFLOW_DATA arasındaki yazma işlemleri zaman alıcı işlemlerdir. Ayrıca taşınan kolonlar sorgu için kullanıldıklarında bu işlemde normal IN_ROW_DATA üzerindeki veri okumasına göre daha uzun sürmektedir. Bu sebeplerden tablo oluştururken bu tür toplam değerlerin 8K'yı geçip geçmediği ayrıca kontrol edilmelidir.
Bu alanların ne sıklıkla sorgulara dahil edildiği düşünülmelidir. Hem IN_ROW_DATA hemde ROW_OVERFLOW_DATA üzerinden senkron okumalar yapmak maliyetli ve zaman alıcı işlemlerdir. Eğer yapılabiliyorsa bu alanlar farklı bir tabloya çekilmelidir. Bu şekilde senkron okuma sayısı azaltılabilir. Farklı tablo join edildiğinde asenkron okuma kullanılacak, iki farklı tablo okunacak ve birleştirilecektir, kısaca ana tablo değerleri daha hızlı elde edilecektir.
Buradaki bir kritik nokta da şudur; Clustered Index Key alanları ROW_OVERFLOW_DATA üzerinde asla olamaz, eğer varchar alanımız Clustered Index Key ise, toplam uzunluğun 8K'yı geçirdiği durumunda, işlemler başarısız olacaktır. Bu konu ile ilgili daha detaylı bilgiye
buradan ulaşılabilir.
Page'lerin gruplanmasıyla Extext'ler oluşur. Extent'ler (boş) alan yönetimlerinin kullanımı için kullanılır. Bir extent 8 ardışık Page'den veya 64K'dan oluşur. Verimli kullanımlar için Extent'ler birden fazla tablo Page'lerini barındırabilir, bu tür Extent'lere Mixed Extent denir. Sadece tek tablo Page'lerini bulunduran Extent'lere Uniform Extent denir. Mixed Extent'ler genelde ufak tablolar için kullanılır. Bir tablo 8 Page boyutunu aşarsa, ilgili tabloya ait Mixed Extent'ler Uniform Extent'lere dönüştürülür. Bu konunun detayını
burada bulabilirsiniz.
Peki tablo türlerine göre daha kabaca yapıları incelersek nasıl bir durum ile karşılaşırız...
Heap
Heap dediğimiz aslında Clustered Index'i olmayan bir tablodur, bu tabloda kayıtlar herhangi bir sırada değildir. Heap'ler yukarıdaki üç allocation unit türlerine sahip olabilir. Hangisi veya hangilerine sahip olacaklarını yukarıda anlatılan row boyutu ve veri türleri belirler. Heap'lerin Clustered Index veya Non-Clustered Index'lerden farkları; Heap Data Page kayıtları sıralı ve birbirleri ile bağlantılı değildir. (Not Linked.) sys.partitions içerisinde, tek Partition'lı Heap'ler için 1 kayıt gelir ve index_id alanının değeri 0'dır. Birden fazla partition kullanılmış ise Partition sayısı kadar kayıt gelecektir.
Aşağıdaki Heap veri tutma şeması size bir fikir verebilir. Konu ile ilgili detaya
buradan ulaşabilrisiniz.
Aşağıdaki şema bir Partition içindir, Heap eğer birden fazla Partition'dan oluşuyorsa, her bir Partition üzerinde aşağıdaki yapıdan birer tane vardır.
Clustered Index
Clustered Index'lerde, Index'ler
B-tree mantığı ile tutulur. En üstte bir Root Node, en altta verileri tutan Leaf Node ve araların Intermediate Level denilen yerde bağlantı Node bulunur.
Leaf Node verileri barındıran Data Page'leri tutarken, Intermediate ve Root Level Node'lar Index bilgilerini barındıran Index Page'lerini tutar. Her bir Index Row, bir değer ve bir pointer tutar. Bu pointer B-tree üzerindeki Intermediate Level Page veya Leaf üzerindeki bir Data Row olabilir. Clustered Index'lerde Page'ler, birbirlerine çift olarak bağlıdır. (Doubly-Linked) Clustered Index üzerinde yapılan aramalarda, bu bağlı olma durumu, aramanın çok hızlı bir şekilde yapılmasına olanak vermektedir.
sys.partitions içerisinde, tek Partition'lı Clustered Index için 1 kayıt gelir
ve index_id alanının değeri 1'dir. Birden fazla partition kullanılmış
ise Partition sayısı kadar kayıt gelecektir. Aşağıdaki şema tek Partition içindir, çoklu Partition kullanımında, aşağıdaki şemadan her bir Partition için ayrı ayrı olacaktır.Konu ile ilgili detaya
buradan ulaşabilrisiniz.
Non-Clustered Index
Non-Clustered Index'ler aslında Clustered Index'ler gibi B-tree yapısındadır. Aralarındaki en önemli fark ise Non-Clustered Index'ler veri tutmazlar, Key kolonları ve Clustered Index'e veya Heap'e referans bilgisini tutarlar. Dolayısıyla Leaf Node Data Page yerine Index Page'lerden oluşur. (Include kolonlar hariç.)
sys.partitions içerisinde, index_id alanı 0'dan büyüktür. Partition'lara göre davranışı Clustered Index ile aynıdır. Bir Partition için oluşan yapısının şeması aşağıdaki gibidir.
Detaylı bilgiye
buradan ulaşabilirsiniz. Non-Clustered Index'lerin key kolon sayısı en fazla 16 olabilir ve bu kolonların toplam uzunluğu 900 byte'ı geçemez.
Non-Clustered Index'lerin Heap, Unique Clustered Index ve Non-Unique Clustered Index'ler ile nasıl eşleştiğinin detaylarını
buradaki yazımdan bulabilirsiniz. Include kolonları ve işleyişleri ile ilgili olarak da
buradaki yazımdan faydalanabilirsiniz.