Bu makalede Page Split konusunu detaylı bir şekilde ele almış olacağız. SQL Server, verileri 8 KB’lık sayfalarda (pages) tutar. Bir tabloya veri eklediğinde ya da bir satır güncellendiğinde, bu veri bu sayfalar içinde yer bulur.
Page Split durumu şudur:
Veri eklemek istediğin sayfa doluysa ve yeni veriyi o sayfaya sığdıramıyorsa, SQL Server o sayfayı ikiye böler (split eder), verinin bir kısmını yeni oluşturduğu sayfaya taşır ve sonra veriyi ekler. Bu işleme Page Split denir.
Örneğin bir tablo düşün:
CREATE TABLE Customers (
ID INT PRIMARY KEY,
Name VARCHAR(50)
)
Bu tabloya sıralı şekilde ID’ye göre veri ekliyorsan, sayfalar arka arkaya dolar. Ama araya yeni bir kayıt eklersen (ID=3 gibi) ve ilgili sayfa dolmuşsa, SQL Server:
- Yeni bir sayfa (page) oluşturur.
- Mevcut sayfadaki bazı verileri yeni sayfaya taşır.
- İstediğin veriyi araya ekler.
- Bu işlem sırasında hem ek işlem maliyeti, hem de geçici kilitlenmeler olur.
Page split’ler performansı negatif etkiler: Fazladan CPU ve IO kullanımı olur. Fragmentation (parçalanma) artar → sorgular yavaşlar.
WITH (NOLOCK) kullanan bir sorgu tam o sırada okuma yaparsa: Verinin bir kısmını eski sayfadan, bir kısmını yeni sayfadan okur, Bu da eksik veya iki kere okuma (double read) gibi hatalara yol açabilir.
Bu işlem nasıl azaltılır:
- Sıralı veri eklemeye çalış. (Clustered Index sırasına uygun)
- Fill factor ayarını düşür. (örneğin %90 yerine %80 bırak, boş yer kalsın)
- Index bakımını düzenli yap (reorganize / rebuild)
REORGANIZE işlemi page split sayacını sıfırlamaz. Page split (sayfa bölünmesi), bir veri sayfası dolduğunda ve yeni veri eklendiğinde, SQL Server’ın bu sayfayı ikiye bölmesiyle oluşur. Bu, genellikle verinin ortasına yapılan eklemelerde olur (özellikle sıralı olmayan insert’lerde). page split sayacı bu işlemden etkilenmez. Bu sayaç, özellikle DMV’lerde (sys.dm_db_index_operational_stats) takip edilir. REORGANIZE, yalnızca mevcut sayfalardaki verileri yeniden düzenler, yani daha verimli bir sıraya sokar.
Index rebuild işlemlerinde ise REBUILD, indeksi tamamen yeni baştan oluşturur. Bu nedenle: Fragmentation tamamen temizlenir. Tüm sayfalar yeni baştan yapılandırılır. Page split sayacı sıfırlanır.
Page split’ler çoğunlukla leaf-level page’lerde yaşanır.
Page Split olayını daha detaylı bir şekilde ele alalım. Bir sayfa (page) dolduğunda ve yeni veri oraya sığmayacak kadar büyükse, SQL Server ne yapar?
Diyelim ki elimizde şöyle bir yapı var:
- Clustered Index var → veriler sıralı tutuluyor (örneğin ID’ye göre).
- Sayfa dolmuş (8 KB kapasite tamamlanmış).
- Yeni bir satır, mevcut sıralamaya göre araya eklenmek isteniyor (örneğin ID=5 ekleniyor ama sayfa 1–10 arası dolu).
SQL Server aşağıdaki adımları izler:
- Yeni bir veri sayfası oluşturur (aynı extent içinde olabilir, farklı da olabilir).
- Mevcut sayfadaki verilerin yaklaşık yarısını alır ve bu yeni sayfaya taşır.
- Yeni veriyi, sıralamaya uygun şekilde eski sayfaya mı yoksa yeni sayfaya mı denk geliyorsa oraya ekler.
- Index pointer’larını (yani üst seviye B-Tree bağlantılarını) günceller.
- Eski ve yeni sayfalar artık veriyi paylaşıyor ve sıralı yapıyı koruyor.
Örneğin elimizde bir page’de şu satırlar var. (ID’ye göre sıralı):
[1] [2] [3] [4] [5] [6] [7] [8]
- Bu sayfa dolu ve sıralı.
- Şimdi ID = 4.5 eklemek istiyoruz.
Page Split Olur:
- SQL Server yeni sayfa açar.
- Diyelim şu şekilde böldü:
Page 1 → [1] [2] [3] [4]
Page 2 → [5] [6] [7] [8]
- Yeni kayıt (4.5) sıralamaya göre Page 2‘ye eklenir:
Page 2 → [4.5] [5] [6] [7] [8]
Böylece sıralama korunur ama performans düşer, çünkü:
- Veri taşındı
- Yeni sayfa yazıldı
- Index güncellendi
Page split sadece INSERT’te olmaz. UPDATE ile satır uzarsa ve mevcut sayfada yer yoksa, aynı şey olabilir. Yani “sadece veri eklerken” değil, güncellerken de page split yaşanabilir.
Aşağıdaki komut ile page split sayısını dolaylı olarak bulunabilir.
SELECT
OBJECT_NAME(ios.object_id) AS TableName,
i.name AS IndexName,
ios.index_id,
ios.leaf_insert_count,
ios.leaf_delete_count,
ios.leaf_update_count,
ios.range_scan_count,
ios.singleton_lookup_count
FROM sys.dm_db_index_operational_stats (DB_ID(), NULL, NULL, NULL) AS ios
JOIN sys.indexes AS i
ON ios.object_id = i.object_id AND ios.index_id = i.index_id
WHERE OBJECTPROPERTY(ios.object_id, 'IsUserTable') = 1;

leaf_insert_count sayısı ile page split sayısını tahmin edebiliriz.
Durum | Açıklama |
---|---|
Page split olduğunda | En az 1 yeni 8 KB page tahsis edilir |
Yeni page hangi extente gider? | SQL Server, mevcut extent doluysa, yeni extent alabilir |
Veriler taşınır | Eski sayfadan bazı satırlar yeni sayfaya taşınır |
Index yapısı güncellenir | B-tree yapısındaki pointer’lar, yeni page’i gösterecek şekilde güncellenir |
Page split hem clustered hem de non-clustered index’lerde olabilir.
Page split’te neden sadece yarısı yeni page’e taşınır. SQL Server veri sırasını korumak zorundadır (özellikle clustered index varsa). Bu yüzden veri eklemesi yapılacak sayfa dolduğunda, veriyi düzgün şekilde dağıtmak için mevcut verinin yaklaşık yarısını yeni sayfaya taşır.
Heap’lerde sıralama olmadığı için “page split” teknik anlamda olmaz. Ancak, eğer bir row update sonucu satır artık mevcut page’e sığmazsa: → SQL Server bu satırı başka bir page’e taşır ve eski yerine bir “forwarding pointer” bırakır. → Bu da performansı düşürür ama “page split” sayılmaz.
Yapı Türü | Page Split Olur mu? | Açıklama |
---|---|---|
Clustered Index | ✅ Evet | Sıralı veri yapısı, araya ekleme zorunluluğu var |
Non-Clustered Index | ✅ Evet | Aynı şekilde sıralı yapı var |
Heap (indexsiz tablo) | ❌ (ama benzeri etki olur) | Forwarded row oluşabilir, ama “split” değildir |
Page Split ve Boşluk Yönetimi
1. Page Boşluğu Yönetimi:
- SQL Server, her sayfayı 8 KB’lık küçük parçalara ayırır.
- Boşluk (internal fragmentation) olduğu sürece, yeni eklenen veri bu boş alanlara yazılmaya çalışılır. İlk başta boş yer herhangi bir page üzerinde doldurulur.
- Bu sayfalar fiziksel olarak doldukça, boş yer kalmaz.
Örnek:
- Diyelim ki 10 numaralı page boş ve eklemeye yeni veriler gelecek.
- İlk başta boş alanlar bu page üzerinde doldurulur.
2. Page Dolduğunda:
- 10 numaralı page tamamen dolarsa ve ekleme yapılacak yer kalmazsa, SQL Server yeni bir page oluşturur (örneğin 350. page).
3. Page Split İşlemi:
- Sayfa dolduktan sonra, yeni veri eklenemediği için page split işlemi gerçekleşir.
- Sayfanın yaklaşık yarısı yeni sayfaya (örneğin 350. page) taşınır. Bu taşıma, genellikle sayfanın ortasında yapılır (ama bazen sayfanın tam ortasında değil, verinin sıralamasına göre).
4. Page Split ve Sıralama:
- Veriler sıralı kalır. Yani, eski sayfanın yarısı taşındığı yeni sayfada veriler yine sıralı olur.
Sonuç:
- Bu durumda, 10 numaralı page’den taşınan veriler 350 numaralı page’e eklenir ve sıralama korunur.
- Bu taşıma mantıksal sıralamayı etkilemez, ancak fiziksel yerleşimi bozar. Bu da logical fragmentation anlamına gelir.
Özetle:
- Sayfa dolduğunda, boşluk varsa ilk başta o boşluğu doldurur.
- Eğer veri 10 numaralı sayfaya eklenmesi gerekiyorsa ama yer yoksa:
- Page Split yapılır.
- Verinin bir kısmı, örneğin 350 numaralı sayfa’ya taşınır.
- Bu taşınan veriler sıralı olur, ancak fiziksel yerleşim bozulur. Bu da logical fragmentation yaratır.
SQL Server’da iki tür fragmentation vardır:
Tür | Açıklama |
---|---|
Logical Fragmentation (External) | Index sırasına göre ardışık olan verilerin fiziksel olarak ardışık page’lerde olmaması durumu. |
Internal Fragmentation | Bir sayfanın içinde boşluk kalması (%100 dolu olmaması) — örn. %50 dolu sayfalar. |
Bir programın 10.5 KB belleğe ihtiyacı var: Kalan 1.5 KB boşa gider → internal fragmentation
Kısacası:
- Internal fragmentation, sayfa içinde boş kalan kullanılmayan alanlardır.
- Sıralama bozukluğu değil, boşluk israfı ile ilgilidir.
- Sayfa sırasının bozulması değil, alanın tam kullanılamaması söz konusudur.
Bu makalede page split konusunu detaylı bir şekilde görmüş olduk. Başka bir makalede görüşmek dileğiyle..
“Helâlinden kazanmak hak yolunda yapılan muhârebe kadar ecirlidir.”