SQL Server’de Ne Zaman Defrag Yapmalıyız

Fragmentation (parçalama) kavramı bilgisayar biliminde bellek, disk gibi kaynaklar üzerindeki birimlerin düzensiz parçalar (fragment) haline dönüşmesi ve bunun sonucunda düzenli boş alanın azalmasıdır. Dağılmış bu parçaları birleştirme işlemine defragmentation (birleştirme) denilir. SQL Server’da uzun süre veritabanı üzerinde yapılan silme, güncelleme, ekleme işlemleri sonucunda veritabanı dosyasında data veya index kayıtları arasında boş alanlar oluşur. Boş alanlar birbirleriyle ilişkili dolu kayıtların arasında olduğu için herhangi bir kayda erişme durumunda dağılmış kayıtlar arasında çok dolaşılacağından ciddi zaman kaybedilmektedir. Veritabanı dosyasındaki boş ve dolu alanları bir tarafa toplayıp dosyayı daha ekonomik, ergonomik kullanmak için belli dönemlerde defragmantasyon yapmak gerekir.
Fragmentation, internal ve external olmak üzere iki kısma ayrılır. External Fragmentation (Dışsal Parçalanma), veritabanı dosyası içerisinde yeteri kadar boş yer olmasına rağmen boş alanların ardışık olmamasından dolayı oluşur. Yani mantıksal olarak birbirleriyle ilişkili data veya index page’ler fiziksel olarak birbirinden uzak durumdadır. External fragmentation’nın oluşması durumunda SQL Server aranılan alana ulaşmak için hayli zaman kaybeder. Bu durumda defragmentation işlemi yapılarak page’lerin birbiriyle sıkılaştırılması sağlanır. Internal Fragmentation (İçsel Parçalanma) ise page’ler içerisindeki boşlukların artmasıyla oluşur. Bu durumda bir page alması gereken kayıttan daha az kayıt için tahsis edilir. Örneğin page’in orta alanında bulunan kayıtlar üzerinde delete veya update işlemini yaptığımızda page’in orta alanında boşluklar oluşabilir. Bu da disk başlığının daha çok gezmesine neden olur.
Kısacası fragmentation gerek disk gerekse veritabanı cephesinde istenmeyen bir durumdur ve veritabanı dosyasının verimli kullanılmasını engeller ve sonuçta sorguların geç yanıtlanmasına neden olur.
Peki SQL Server’da ne zaman defrag işlemi yapılmalıdır, indekler ne zaman yeniden düzenlenmelidir. Bu işlem için DBCC SHOWCONTIG () komutu kullanılır. Bu komut parametre olarak aldığı tablonun data ve index’lerin fragmentasyon durumunu hakkında bilgi verir.

--Musteri tablosu hakkında bilgi alalım
DBCC SHOWCONTIG (Musteri) 

--Musteri tablosu hakkında kısa bilgi alalım
DBCC SHOWCONTIG (Musteri, 1) WITH FAST

--Musteri tablosunun PK_Musteri indexi hakkında bilgi alalım
DBCC SHOWCONTIG (Musteri,PK_Musteri) 

--Mevcut veritabanının tüm table ve indexleri hakkında bilgi alalım
DBCC SHOWCONTIG WITH TABLERESULTS, ALL_INDEXES

Bu komut çalıştırdığımızda aşağıdaki gibi değerleri listelenir.

DBCC SHOWCONTIG scanning 'Musteri' table...
Table: 'Musteri' (757577737); index ID: 1, database ID: 11
TABLE level scan performed.
- Pages Scanned................................: 1
- Extents Scanned..............................: 1
- Extent Switches..............................: 0
- Avg. Pages per Extent........................: 1.0
- Scan Density [Best Count:Actual Count].......: 100.00% [1:1]
- Logical Scan Fragmentation ..................: 0.00%
- Extent Scan Fragmentation ...................: 0.00%
- Avg. Bytes Free per Page.....................: 7964.0
- Avg. Page Density (full).....................: 1.61%

Buradaki değerlere bakarak defrag ihtiyacımızı belirleyebiliriz.
Pages Scanned : Tablo veya indexe ait page sayısını belirtir. Fragmantasyon olması durumunda defrag işleminden sonra bu sayının düşmesi beklenir.
Extents Scanned : Tablo veya indexe ait extent sayısını belirtir. Her extent içerisinde 8 adet page bulunur. Bu ifadenin karşısındaki rakam “Pages Scanned / 8¨ sonucundan büyük çıkarsa veritabanı dosyasında fragment oluştuğu söylenebilir.
Extent Switches : Extent’ler arasındaki switch değeridir. SQL Server’in bir tablo veya indexi tararken bir extent’ten diğerine kaç kere atladığını belirtir. Bu rakamın taranılmış extent sayısından 1 eksik olması beklenir. Rakamın farklı çıkması Fragmantasyon sorunu olduğunu gösterir. Bu değerin “Extents Scanned” değerinden 1 eksik olması SQL Server’in tarama esnasında ilk extent’i bir ‘extent swith’ olarak saymamasından kaynaklanmaktadır.
Avg. Pages per Extent : “Pages Scanned / Extents Scanned” bölümüne eşit olup extent içerisindeki ortalama page sayısını verir. Çok sayfalı veritabanlarında bu sayının 8’e yakın olması beklenir. Bu sayı 8’den küçük ise Fragmantasyon sözkonusu olduğunu söyleyebiliriz.
Scan Density [Best Count: Actual Count] : Fragmantasyon sorunun en belirgin göstergeci olup %90-%100 arasında bir değer olması beklenir. 100’den küçük olması durumunda defrag işlemine ihtiyaç duyulduğunu gösterir.
Logical Scan Fragmentation : Mantıksal olarak bulunması gereken yerde olmayan page’lerin oranını gösterir. Değerin %1’in altında olması beklenir. 1’den ne kadar fazlaysa o kadar yoğunlukta fragmentation oluştuğunu gösterir.
Extent Scan Fragmentation : Extent’ler arasındaki boşluğun yüzdeliği olup 0 olması beklenir.
Avg. Bytes Free per Page : Sayfalardaki ortalama boş alanı belirtir. Rakamlar çok yüksek olması çok az dolu page’in olduğu anlamına gelir. Burada row’lardaki kayıtların büyüklüğü önemli rol oynar.
Avg. Page Density (full) : Önceki değerin yüzdelik gösterimidir. Yüksek yüzdelik (%90-%100) idealdir. Düşük yüzde değeri fragmentasyon olduğu anlamına gelir.
Bu değerleri gözönünde bulundurarak tablo veya indeksleri defrag edip etmeyeceğimize karar verebiliriz. Defrag işleminin temel mantığı tablo üstündeki indeksleri yeniden düzenlemektir. Bunun için ya indexler kaldırılıp yeniden oluşturulur ya da DBCC DBREINDEX veya DBCC INDEXDEFRAG komutları kullanılarak parçalar bütünleştirilir. Her iki komut ta temel olarak indeksleri iyileştirmek için kullanılır.

  • DBREINDEX en az bir tablo alacak şekilde tek parametre alır. INDEXDEFRAG ise veritabanı adı, tablo adı ve index adı olmak üzere üç parametre alır.
  • DBREINDEX komutu parametre olarak aldığı tabloyu yeniden indeksler yani tablonun üstündeki tüm indeksleri yeniden oluşturur. Yazım biçimi DROP INDEX veya CREATE INDEX gibi ifadelerden daha kısa olduğu için tercih edilir. INDEXDEFRAG ise parametre olarak aldığı indeksi sadece defragment eder yani parçalar fiziksel olarak yanyana getirilerek birleştirilir. Indeks yeniden oluşturulmadığı için DBREINDEX kadar performans sağladığını söyleyemeyiz.
  • DBREINDEX komutu tüm indeks yeniden oluşturulancaya kadar tabloları lock eder ve kullanıcıların verilere ulaşmasını bekletir. INDEXDEFRAG ise online bir operasyon olup kilitleri uzun süre tutmaz bir taraftan da kullanıcıların verilere erişmesine izin verir.
  • DBREINDEX komutu çalıştırıldıktan sonra defrag edilecek bir alan olmadığı için ardından INDEXDEFRAG komutunu çalıştırmaya gerek yoktur.
  • INDEXDEFRAG esnasında herhangi bir sorun oluşur ve komut durdurulursa herşey rollback edilmez az da olsa defrag yapılmıştır fakat DBREINDEX komutundaki bir başarısızlık herşeyi geri aldığı için defrag işlemini yeniden başlatmak gerekir.
  • DBREINDEX komutu INDEXDEFRAG komutuna oranla log dosyasını daha çok büyütür.

SQL SERVER 2005’te DBREINDEX ve INDEXDEFRAG komutları destek verildiği gibi bu komutlarla aynı göreve sahip ALTER INDEX REORGANIZE (DBCC INDEXREFRAG) veya ALTER INDEX REBUILD (DBCC DBREINDEX) ifadesi kullanılır. REORGANIZE parametresi, indeksleri yeniden yapılandırır. REBUILD parametresi, indeksi silip yeniden oluşturur. Bununla birlikte SQL Server 2005’te bir indeksi varsa silip yeniden oluşturup düzenlemek için CREATE INDEX komutunun DROP_EXISTING = { ON | OFF } parametresi de kullanılabilir.
Tablolar üzerinde yoğun bir şekilde ekleme, silme, güncelleme işlemleri yapılıyor ve page’lerdeki boşluk alanı %50 üzerindeyse ALTER INDEX ..REBUILD kullanılması tavsiye edilir. Tabi bu işlemi her zaman değil belli dönemlerde DBCC SHOWCONTIG komutunun sonucuna göre yapmak daha mantıklı olacaktır.
Üzerinde en çok update/insert işleminin yapıldığı ve bu neden fragmentlerin oluştuğu 37 milyon kayıt içeren f_mov tablosunun defrag öncesi ve sonrası aşağıdaki tabloda gösterilmiştir.

Faktör Defrag Öncesi Değer Defrag Sonrası Değer
Pages Scanned…………: 1987464 1781008
Extents Scanned……….: 250285 223654
Extent Switches……….: 674964 223653
Avg. Pages per Extent……..: 7.9 8.0
Scan Density [Best Count:Actual Count]…: 36.81% [248433:674965] 99.54% [222626:223654]
Logical Scan Fragmentation……: 43.51% 0.04%
Extent Scan Fragmentation…….: 14.72% 1.93%
Avg. Bytes Free per Page…….: 959.5 162.4
Avg. Page Density(full)…….: 88.15% 97.99%

Tablodaki bazı değerleri yorumlayalım. “Extent Switches” faktörü daha önce 674.964 iken defrag sonrası 223.653 olmuştur. Defrag öncesi SQL Server bir extent’ten diğerine 250.000 kere daha fazla atlama yapıyordu. Ayrıca bu değer olması gerektiği gibi bu değer “Extents Scanned” değerinden 1 eksiktir. Nitekim “Scan Density” faktörü, %36 ike defrag sonra %100’e yaklaşmıştır. “Pages Scanned” faktörü yok edilmiş sayfa sayısını göstermektedir. Taranan sayfa sayısı yaklaşık 200.000 sayfa azalmıştır. “Avg. Bytes Free per Page” değeri defrag sonrası sayfaları ortalama boşluk alanını 959,5’ten 162,4’e düşürmüştür.
SQL Server 2005’te ne tür bir internal veya external türünde fragmentasyonun oluşup oluşmadığını anlamanın diğer yolu da aşağıdaki standart T-SQL Script’i çalıştırmaktır. Bu script Deneme veritabanı altındaki Musteri tablosuna ait fragmantasyon bilgisini verir.

SELECT CAST(DB_NAME(database_id) AS varchar(20)) AS [Database Name],
CAST(OBJECT_NAME(object_id) AS varchar(20)) AS [TABLE NAME], Index_id,
Index_type_desc, Avg_fragmentation_in_percent, Avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('Deneme'),
OBJECT_ID('Musteri'),NULL,NULL,'Detailed')

Deneme isimli veritabanı içindeki tüm tablolar hakkında bilgi almak için aşağıdaki script kullanılır.

SELECT CAST(DB_NAME(database_id) AS varchar(20)) AS [Database Name],
CAST(OBJECT_NAME(object_id) AS varchar(20)) AS [TABLE NAME], Index_id,
Index_type_desc, Avg_fragmentation_in_percent, Avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('Deneme'),NULL,NULL,NULL,'Detailed')

Bu fonksiyonu son 3 kolonuna bakılarak defrag için aşağıdaki yorumlar yapılabilir.
Avg_fragmentation_in_percent kolonu >5 ve <30 ise=”” indeksleri=”” reorganıze=”” etmek=”” yani=”” alter=”” ındex=”” reorganıze=”” komutunu=”” kullanmalıyız.=”” eğer=”” değer=””>30 ise indeksleri REBUILD etmek yani ALTER INDEX REBUILD komutunu çalıştırmak gerekir. Bu kolon external fragmentation yani mantıksal parçalanma olduğunun göstergecidir.
Avg_page_space_used_in_percent: Bu değer indeks sayfasının doluluğunu gösterir. Bu değer <75% ve=””>60 ise indekslerin REORGANIZE değilse REBUILD edilmesi gerekir. Bu kolon internal fragmentation olduğunun göstergecidir.
Kısaca DBCC SHOWCONTIG komutunu veya sys.dm_db_index_physical_stats fonksiyonu kullanarak indekslerin parçalanma durumları kontrol edilir. Bu fonksiyonu sorgulanma yöntemi SHOWCONTIG komutuna göre sisteme daha az yük bindirir ve kilitleri daha kısa tutar. Indekslerdeki parçalı alanları bütünleştirmek için ALTER INDEX REBUILD veya ALTER INDEX REORGANIZE komutları kullanılır.

SQL Server’de Ne Zaman Defrag Yapmalıyız” hakkında 3 yorum

  1. Meriç

    Ahmet Bey merhaba,çok büyük bir tablom var. Bunu veritabanına ait 2.file group’a aktarmamın bir yolu var mıdır. SQL 2000 kullanıyorum.

    Cevapla
  2. Ahmet Kaymaz Yazar

    Merhaba Meriç,bunu iki şekilde yapabilirsin;1 – İkinci file group üzerinde yeni tabloyla aynı şemaya sahip bir tablo oluşturulur ve ardından eski tablodaki verileri yeni tabloya aktarılır.2 – SQL Server Enterprise Manager içerisinde tabloyu sağ tıklayıp “Design Table” menüsünü tıklayalım. Tasarımı aşamasında herhangi bir kolonu sağ tıklayıp Properties penceresini açtıralım. Bu pencerede “Table Filegroup” ve “Text Filegroup” değerini düzenleyerek bir tabloyu başka bir filegroup’a taşıyabilirsin. “Text Filegroup” değeri tablodaki text, image gibi büyük veri tipli kolonları başka bir dosya grubuna taşımak için kullanılır.

    Cevapla
  3. Gülşah Masat

    Merhaba,

    Page’in orta alanında bulunan kayıtlar üzerinde delete veya update işlemini yaptığımızda page’in orta alanında boşluklar oluşabilir. Bu da disk başlığının daha çok gezmesine neden olur.

    Sonuçta Sql de index yapısı olan Btree de ayrı ayrı bulunmaktadır. Yeni page eklendiğinde de istenen o kayıta leaf level da bulunan ilgili page e direkt giderek ulaşabilir. Neden disk başlığı daha çok gezmiş oluyor? Bunu açıklayabilirseniz çok sevinirim.

    Teşekkürler, iyi çalışmalar.

    Cevapla

Bir cevap yazın

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