Bu makalede Data Shrink işlemiyle mevcut verilerimiz default filegroup altında oluşturma işlemi ele almış olacağız. Konuya geçmeden önce shrink işleminin ne olduğuna değinmiş olalım. Veritabanımızı bazen data ve log dosyamızı shrink etme gibi bir sorunla karşılaşa biliriz. Çalışan bir veritabanında Data dosyaları shrink edilmesi önerilmez. Çünkü shrink edilince veritabanı bozulma ihtimali çok yüksek olur. Shrink edilen data dosyalarındaki indexs fragmantation çok yüksek oranda artacaktır. Yapacağımız örnekte ise kullanılmayan filegroupdaki datalarımız default olan primary file group’a alma işlemini ele almış olacağız. Log dosyası nasıl shrink edilir ve ne gibi senaryoların olduğunu öğrenmek için ilgili makaleyi okumalısınız.
Not: Ndf uzantılı filegroup shrink edildikten sonra silinebilir. Fakat mdf uzantılı filegroup sadece shrink edilebilir.
Not: Bir tablonun verilerinin farklı data file’lara yazılabilmesi için tüm data file’ların tablo ile aynı filegroup’da olması gerekiyor.
Şimdi yapacağımız örnekte eski datalarımızın olduğu file groupta bulunan veriyi primary filegroup üzerine shrink işlemini görmüş olacağız. Amaç sadece yolunu göstermek verilerin yeni filegroup’a taşınması için aynı tablo yapısının olması gerekmektedir.
Aşağıdaki komut ile hangi tablonun hangi filegroup üzerinde olduğunu bulabiliriz. Partition tablolarında filegroup öğrenilmesi isteniyorsa makale sonundaki script çalıştırılır.
SELECT distinct o.[name], o.[type], f.[name] FROM sys.indexes i
INNER JOIN sys.filegroups f
ON i.data_space_id = f.data_space_id
INNER JOIN sys.all_objects o
ON i.[object_id] = o.[object_id]
AND o.type = 'U' -- User Created Tables
GO

Veritabanı üzerine sağ tıklayarak Task>Shrink>Files kısmına girilir.

Gelen ekranda File Type kısmında Data ifadesini seçmemiz gerekiyor. Filegroup sekmesinde hangi filegroup’u shrink yapmak istiyorsak ilgili filegroup’u seçiyoruz. Primary olan filegroup’u seçtikten sonra devam ediyoruz.

Location kısmında mevcutta olan dosyamızın nerde olduğuna dair bilgiler yazmaktadır.
Currently Allocated Space kısmında data dosyamızın maksimum büyüklüğünü görebiliriz.
Available free space kısımında data dosyasının ne oranında boş olduğu görünüyor.

Shrink action kısmında 3 seçenek karşımıza çıkmaktadır.
Release unused space kullanılmayan alanların tamamını işletim sistemine iade etmek ister. Büyük databaselerde bu yapı kullanılmaz çünkü kullanılmayan alan büyükse hemen işletim sistemine iade edemez.
Release unused space seçeneğindeki sıkıntıdan dolayı ikinci seçenekte bulunan Reorganize pages before releasing unused space kısmı kullanarak kademeli kademeli disk alanını işletim sistemine iade etmek gerekir. Başlangıç olarak default olarak mevcut boyut gelmektedir. Burada değer hangi değere düşürmek istiyorsak o değer mb cinsinden girilmelidir.
Son seçenekte bulunan Empty file by migrating the data to other files in the same filegorup ise veritabanı altında ikinci bir data dosyası oluşturduktan sonra ikinci data dosyasını shrink edip eski data dosyasının üzerine yazıp daha sonra data dosyamızı silebiliriz.
Not: .mdf uzantılı data dosyalarını silemeyiz. Sadece .ndf uzantılı data dosyalarını silebiliriz.
Ben örneğimde FG2024 filegroup altında bulunan datayı Primary filegroup altına atacağım için 3. seçenek olan Empty file by migrating the data to other files in the same filegorup’u işaretliyorum.
Files sekmesinden önce data dosyamı normal bir şekilde shring edip boş alanları işletim sistemine iade ettikten sonra Empty file by işlemi gerçekleştirip farklı filegroup’a verilerimi atıyorum.
Yukarıdaki işlemler yapılmadan önce aşağıdaki işlemler sırasıyla yapılabilir. En sonda shrink işlemi yapılabilir.
1. Tabloyu PRIMARY Filegroup’a Taşı
Eğer FILE tablosunun clustered index’i varsa, PRIMARY üzerine yeniden oluşturarak tabloyu taşıyabiliriz.
A. Clustered Index varsa:
Clustered index varsa yeniden oluştur (taşıma işlemi yapar)
CREATE CLUSTERED INDEX IX_FILE_CL
ON dbo.FILE(ID) -- uygun bir kolon belirt
WITH (DROP_EXISTING = ON)
ON [PRIMARY];
Bu işlem, tabloyu ve tüm verisini PRIMARY filegroup’a taşıyacaktır.
B. Clustered Index yoksa (HEAP ise):
- Yeni bir tablo oluştur, PRIMARY filegroup’ta:
SELECT * INTO FILE_TEMP FROM dbo.FILE;
- Eski tabloyu sil, yeniden adlandır:
DROP TABLE dbo.FILE;
EXEC sp_rename 'FILE_TEMP', 'FILE';
Not: Bu işlemde constraints, triggers, indexes vs. tekrar oluşturulmalıdır. Otomatik taşıma sağlamaz.
3. Shrink Empty File
Tablonun taşınmasıyla birlikte, FG2024 altında artık veri kalmadıysa, data file shrink işlemi yapılabilir.
-- Data file adını bul
SELECT name FROM sys.master_files
WHERE database_id = DB_ID() AND data_space_id IN
(SELECT data_space_id FROM sys.filegroups WHERE name = 'FG2024');
-- Shrink işlemi: boş file sıkıştırılır
DBCC SHRINKFILE (N'YourDataFileName.ndf', EMPTYFILE);
4. Dosya tamamen boşaltıldıysa artık sistemden kaldırılabilir:
ALTER DATABASE MyDatabase
REMOVE FILE YourDataFileName;
Önemli Notlar:
- Filegroup’lar doğrudan silinemez, ama içlerindeki tüm veriler taşındıysa dosyalar silinebilir.
- Clustered index taşıma işlemi hem tabloyu hem veriyi taşır.
- Nonclustered index’ler, LOB veriler (nvarchar(max), text, image vs.) başka filegroup’ta olabilir; ayrıca kontrol edilmeli.
Bu işlemle birlikte:
- FG2024 altındaki FILE tablosu PRIMARY filegroup’a taşındı.
- FG2024 filegroup’a bağlı veri dosyası boşaltıldı ve shrink edildi.
- Gerekirse bu dosya tamamen sistemden kaldırıldı.
Not: Aşağıdaki komut ile veritabanı altında bulunan partition tablo ve partition sız tabloları getirmektedir. Aynı zamanda tüm tabloların filegroupları görülmektedir.
SELECT
SCHEMA_NAME(t.schema_id) AS [Schema],
t.name AS [Table Name],
CASE
WHEN ps.data_space_id IS NOT NULL THEN 'YES'
ELSE 'NO'
END AS [Is Partitioned],
ISNULL(ps.name, 'N/A') AS [Partition Scheme],
ISNULL(pf.name, 'N/A') AS [Partition Function],
-- Filegroup bilgisi (partition olmayanlar için)
CASE
WHEN ps.data_space_id IS NULL THEN fg.name
ELSE 'See Partition Details Below'
END AS [Filegroup (Non-Partitioned)],
-- Partition detayları (partition olanlar için)
p.partition_number AS [Partition Number],
pfg.name AS [Partition Filegroup],
p.rows AS [Rows in Partition],
prv.value AS [Partition Boundary Value]
FROM sys.tables t
INNER JOIN sys.indexes i ON t.object_id = i.object_id AND i.index_id IN (0, 1) -- Heap or Clustered Index
INNER JOIN sys.data_spaces ds ON i.data_space_id = ds.data_space_id
LEFT JOIN sys.partition_schemes ps ON ds.data_space_id = ps.data_space_id
LEFT JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
LEFT JOIN sys.filegroups fg ON ds.data_space_id = fg.data_space_id AND ps.data_space_id IS NULL
LEFT JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
LEFT JOIN sys.destination_data_spaces dds ON ps.data_space_id = dds.partition_scheme_id AND p.partition_number = dds.destination_id
LEFT JOIN sys.filegroups pfg ON dds.data_space_id = pfg.data_space_id
LEFT JOIN sys.partition_range_values prv ON pf.function_id = prv.function_id
AND p.partition_number = CASE pf.boundary_value_on_right
WHEN 1 THEN prv.boundary_id + 1
ELSE prv.boundary_id
END
WHERE t.is_ms_shipped = 0 -- Only user-created tables
ORDER BY [Schema], [Table Name], [Partition Number];

Bu makalede verinin yeni file group’a nasıl taşındığını ve data shrink olayını görmüş olduk.
NOT: Data dosyası shrink edildikten sonra fragmentation değerini artacağını yukarıda belirtmiştik. Shrink işlemi yapıldıktan sonra rebuild ve reorganize yapılması gerekmektedir. 2. bir yöntem ise tablo filegroup belirlendikten sonra shrink yapılacak Filegroup altında yeni bir data dile oluşturulup empty file shrink yapılması gerekmektedir. Daha sonra diğer data file boyutu sıfırlandıktan sonra silinebilir.
Başka bir makalede görüşmek dileğiyle..
“Sonra geceyi ve gündüzü, güneşi ve ayı sizin hizmetinize O verdi. Bütün yıldızlar da O’nun emrine boyun eğmişlerdir. Gerçekten bunda aklını kullanan bir toplum için nice ibretler, dersler vardır.” Nahl-12
1 thought on “MSSQL Server Primary Dışındaki Bir Filegroup’u Shrink Etmek – Empty File Shrink”