Table block with one column pulled out, representing safely dropping unused columns in SQL Server

SQL Server’da Kullanılmayan Kolonları Güvenle Silmek: Bağımlılıkları Yöneten Script

Kullanılmayan SQL Server kolonlarını emekliye ayırmak için iki aşamalı yöntem ve default, check, foreign key kısıtlamaları, index’ler ve istatistiklerle birlikte silme script’ini üreten sorgu.

Temmuz 18, 2023

Bir kolonu tablodan kaldırmak, uygulama artık o kolonu kullanmıyorsa basit görünür: ALTER TABLE ... DROP COLUMN. Ama kolon bir default constraint’e, bir check constraint’e, bir foreign key’e, bir index’e ya da elle oluşturulmuş bir istatistiğe bağlıysa komut hata verir. Daha da önemlisi, kolonu gerçekten kimsenin kullanmadığından emin olmadan silmek, bir raporun ya da gece job’ının aniden bozulması demektir.

Bu yazıda kolonları güvenle emekliye ayırmak için iki aşamalı bir yöntemi ve silme script’ini, bağımlı nesneleriyle birlikte otomatik üreten bir sorguyu paylaşıyoruz.

SQL Server Danışmanlığı

Veritabanınızda kullanılmayan yapılar mı birikti?

Aryasoft, kullanılmayan tablo, kolon ve index'leri bağımlılıklarıyla birlikte çıkarır ve güvenli bir temizlik planı hazırlar.

Destek Alın

İki Aşamalı Yöntem: Önce İşaretle, Sonra Sil

Kullanılmadığını düşündüğünüz bir kolonu doğrudan silmek yerine önce yeniden adlandırarak “emekliye ayrıldı” olarak işaretleyin. Örneğin kolonun adına dep_ öneki ekleyin:

EXEC sys.sp_rename N'dbo.Musteri.FaksNo', N'dep_FaksNo', N'COLUMN';

Kolonu hâlâ kullanan bir sorgu, procedure ya da rapor varsa, ad değişikliğinden sonra “Invalid column name” hatası verir ve kendini gösterir. Bu hata geri alınması kolay bir hatadır: kolonu eski adına döndürmek yeterlidir; veri kaybolmamıştır. Belirli bir bekleme süresi boyunca (örneğin bir tam iş döngüsü, ay sonu kapanışı dahil) hata gelmezse, kolon gerçekten kullanılmıyordur.

Uyarı

sp_rename, kolona başvuran stored procedure, view ve fonksiyonları otomatik güncellemez; bu nesneler yeni adla derlenemediği için çalıştıklarında hata verir. Bu, yöntemin amacıdır; ama yeniden adlandırmadan önce bağımlılıkları kontrol edin ve değişikliği uygulama ekipleriyle paylaşın.

Bazı bağımlılıklar yeniden adlandırmanın kendisini engeller: Kolonu bir CHECK constraint, bir computed column, filtered index’in WHERE koşulu ya da schema-bound bir view veya fonksiyon kullanıyorsa sp_rename Msg 15336 ya da Msg 5074 hatası verir. Testlerimizde default constraint, index, istatistik ve foreign key’ler adlandırmayı engellemedi. Bu hatayı alırsanız bağımlı nesnenin script’ini alın, nesneyi kaldırın, kolonu yeniden adlandırın ve nesneye hâlâ ihtiyaç varsa yeni adla yeniden oluşturun.

Bağımlılıkları bulmak için bir tabloyu kullanan nesneleri bulma rehberimizdeki kolon düzeyindeki sorguyu kullanın.

Silme Script’ini Üretmek

Bekleme süresi dolduktan sonra, aşağıdaki sorgu adı dep_ ile başlayan tüm kolonlar için gereken komutları doğru sırayla üretir: önce kolona bağlı constraint’ler, index’ler ve istatistikler, sonra kolonun kendisi. Sorgu yalnızca script üretir, hiçbir şeyi silmez.

DECLARE @prefix sysname = N'dep[_]%';   -- alt çizgi LIKE'ta joker olduğu için kaçırıldı

WITH hedef AS (
    SELECT c.object_id, c.column_id,
           QUOTENAME(OBJECT_SCHEMA_NAME(c.object_id)) + N'.' + QUOTENAME(OBJECT_NAME(c.object_id)) AS tablo,
           QUOTENAME(c.name) AS kolon
    FROM sys.columns AS c
    JOIN sys.tables  AS t ON t.object_id = c.object_id
    WHERE c.name LIKE @prefix
)
SELECT adim, komut
FROM (
    -- 1. Default constraint'ler
    SELECT 1 AS adim, N'ALTER TABLE ' + h.tablo + N' DROP CONSTRAINT ' + QUOTENAME(dc.name) + N';' AS komut
    FROM hedef AS h
    JOIN sys.default_constraints AS dc ON dc.parent_object_id = h.object_id AND dc.parent_column_id = h.column_id
    UNION ALL
    -- 2. Kolon düzeyindeki check constraint'ler
    SELECT 2, N'ALTER TABLE ' + h.tablo + N' DROP CONSTRAINT ' + QUOTENAME(cc.name) + N';'
    FROM hedef AS h
    JOIN sys.check_constraints AS cc ON cc.parent_object_id = h.object_id AND cc.parent_column_id = h.column_id
    UNION ALL
    -- 3. Kolonu içeren foreign key'ler
    SELECT DISTINCT 3, N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + N'.'
                       + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) + N' DROP CONSTRAINT ' + QUOTENAME(fk.name) + N';'
    FROM hedef AS h
    JOIN sys.foreign_key_columns AS fkc
         ON (fkc.parent_object_id = h.object_id AND fkc.parent_column_id = h.column_id)
         OR (fkc.referenced_object_id = h.object_id AND fkc.referenced_column_id = h.column_id)
    JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
    UNION ALL
    -- 4. Kolonu içeren index'ler (gözden geçirin: index başka kolonları da içerebilir)
    SELECT DISTINCT 4, N'DROP INDEX ' + QUOTENAME(i.name) + N' ON ' + h.tablo + N';  -- gözden geçirin'
    FROM hedef AS h
    JOIN sys.index_columns AS ic ON ic.object_id = h.object_id AND ic.column_id = h.column_id
    JOIN sys.indexes AS i ON i.object_id = ic.object_id AND i.index_id = ic.index_id
    WHERE i.is_primary_key = 0 AND i.is_unique_constraint = 0
    UNION ALL
    -- 5. Elle oluşturulmuş istatistikler
    SELECT DISTINCT 5, N'DROP STATISTICS ' + h.tablo + N'.' + QUOTENAME(s.name) + N';'
    FROM hedef AS h
    JOIN sys.stats_columns AS sc ON sc.object_id = h.object_id AND sc.column_id = h.column_id
    JOIN sys.stats AS s ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
    WHERE s.user_created = 1
    UNION ALL
    -- 6. Kolonun kendisi
    SELECT 6, N'ALTER TABLE ' + h.tablo + N' DROP COLUMN ' + h.kolon + N';'
    FROM hedef AS h
) AS s
ORDER BY adim, komut;

Kritik

Üretilen script’i doğrudan çalıştırmayın. Özellikle 4. adımdaki index’ler başka kolonları da içerebilir ve başka sorgular tarafından kullanılıyor olabilir; bir index’i silmek o sorguları yavaşlatabilir. Kolon primary key ya da unique constraint’in parçasıysa script onu silmez; bu durum ayrıca değerlendirilmelidir. Script’i gözden geçirin, test ortamında çalıştırın ve üretimde çalıştırmadan hemen önce bir yedek alın.

Alan Neden Hemen Geri Gelmiyor?

DROP COLUMN çoğunlukla bir meta veri işlemidir: kolon tanımdan kalkar ama verinin kapladığı alan sayfalarda kalır. Alanı geri kazanmak için tabloyu yeniden oluşturun:

-- Clustered index'i olan tablolarda
ALTER INDEX ALL ON dbo.Musteri REBUILD;

-- Heap tablolarda
ALTER TABLE dbo.Musteri REBUILD;

Büyük tablolarda bu işlem kaynak tüketir ve log üretir; bakım penceresinde yapın. Tablo boyutlarını önce ve sonra ölçmek için tablo boyutu rehberimize bakın.

Kontrol Listesi

  • Kolonun bağımlılıkları kontrol edildi ve uygulama ekipleriyle paylaşıldı.
  • Kolon önce dep_ önekiyle yeniden adlandırıldı ve bir iş döngüsü boyunca beklendi.
  • Silme script’i üretildi, gözden geçirildi ve test ortamında çalıştırıldı.
  • Silinecek index’lerin başka sorgulara etkisi değerlendirildi.
  • Üretimde çalıştırmadan önce yedek alındı; ardından alan geri kazanıldı.
Kolon bir default constraint, check constraint, foreign key, index ya da elle oluşturulmuş istatistik tarafından kullanılıyorsa ALTER TABLE DROP COLUMN hata verir. Önce bu bağımlı nesnelerin kaldırılması gerekir.
Bağımlılık sorgularıyla kontrol edin, ardından kolonu yeniden adlandırarak bir iş döngüsü boyunca bekleyin. Kolonu kullanan kod varsa hata vererek ortaya çıkar ve ad kolayca geri alınabilir.
DROP COLUMN çoğunlukla meta veri işlemidir. Alanı geri kazanmak için index’leri ya da heap tabloyu yeniden oluşturun.
Primary key ve unique constraint’ler tablonun bütünlüğünün parçasıdır ve genellikle başka tablolar tarafından başvurulur; bunların kaldırılması ayrıca planlanmalıdır.

SQL Server Danışmanlığı

Veritabanınızı güvenle sadeleştirin

Aryasoft’un kıdemli DBA ekibi kullanılmayan tablo, kolon ve index’leri bağımlılıklarıyla birlikte çıkarır; iki aşamalı, geri alınabilir bir temizlik planıyla veritabanınızı sadeleştirir.

4.7/5