Veritabanımı Küçültmem Gerekiyor - Çok fazla alan açtım


35

Bu soru burada çeşitli şekillerde soruluyor, fakat soru aşağıya doğru kayıyor:

Veritabanını küçültmenin riskli olduğunu biliyorum. Bu durumda, çok fazla veri kaldırdım ve bir daha asla kullanmayacağım.

  • Veritabanımı nasıl daraltabilirim? Hangi dosyaları küçültürüm?
  • Bunu yaparken düşüncelerim neler olmalı?
  • Sonra bir şey yapmalı mıyım?
  • Ya büyük bir veritabanıysa? Daha küçük artışlarla küçültebilir miyim?

2
Bir süre önce bununla mücadele ettim: dba.stackexchange.com/questions/47310/… Cevabımdaki deneyimimi özetlemeye çalıştım
Csaba Toth

Yanıtlar:


30

Bazı İlk Uyarılar:

  1. Genellikle bir kötü uygulama olarak bilinir şimdiye (Günlük dosyaları olarak başka bir sorun olduğu bir üretim veritabanı veya veri dosyasını küçültmek bu soru hakkında görüşmelerin). İnsanlara, "doğru boyutlandırma" ve iyi planlama hakkında bahsettiğim blog yazılarında veritabanlarını daraltmalarını tavsiye ediyorum. Orada yalnız değilim ( Paul Randal , Brent Ozar , sadece birkaç bağlantı daha sağlamak için). Bir veri dosyasını ya da veri tabanı parça dizinlerini küçültmek, kaynaklarınız üzerinde yavaş ve zahmetlidir, sisteminizi boşaltabilir ve genellikle yapılması gereken kötü bir şeydir.
  2. Bu durumda, hepimiz riskin var olduğunu biliyoruz, bununla başa çıkmaya hazırız , ancak bir daha asla ihtiyacımız olmayacağını bildiğimiz çok fazla yer bıraktık . Yani bu özel davada - daralma seçeneklerimizden biri olarak çok anlamlı.

Endişeleri ve riskleri okuduysanız ve bu küçültmeyi yine de yapmanız gerekiyor, çünkü önemli miktarda yer bıraktınız , umarım bu cevabın geri kalanı size yardımcı olacaktır. Ancak riskleri göz önünde bulundurun.

Burada ele alınan iki ana yaklaşım var:

1.) Küçült Evet, gerçek küçültmeyi yapın - DBCC SHRINKFILEyerine kullanmayı düşünün DBCC SHRINKDATABASE, neyin küçüleceği ve nasıl kontrol edildiği konusunda daha fazla kontrol sahibi olun. Bu , kesin olarak performansın düşmesine neden olacaktır - çok fazla GÇ işlemi yapan büyük bir işlemdir. Sen olabilir , potansiyel olarak giderek küçülüyor bir hedef boyuta tekrarlanan ruh doktoru paçayı.

Bu, yukarıdaki DBCC SHRINKFILElinkte "A.)" örneğidir. Bu örnekte bir veri dosyası 7 MB'lık hedef boyutuna küçültülmektedir. Bu biçim, kapalı kalma sürenizin izin verdiği şekilde tekrar tekrar küçültmek için iyi bir yoldur. Bunu, performansın nasıl göründüğünü ve bir artışın ne kadar düşük / yüksek olabileceğini görmek ve üretimde beklenen zamanlamayı belirlemek için geliştirme üzerine yapılan testlerde yaparım. Bu bir çevrimiçi işlemdir - sistemdeki kullanıcılarla veritabanının küçültülmesine erişerek çalıştırabilirsiniz, ancak neredeyse garanti edilen performans düşüşü olacaktır. Bu yüzden sunucuya ne yaptığınızı izleyin ve izleyin, ideal olarak bir kesinti penceresi veya daha hafif bir aktivite süresi seçin.

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

Her Zaman Unutmayın: - her daraltdığınızda, dizinlerinizi parçalıyorsunuz ve uzun süre boyunca topaklarda daralmaya devam ederseniz, bir dizin yeniden oluşturmalısınız. Hepsini tek bir pencerede yapamıyorsanız, şimdi her seferinde bu maliyete katlanıyorsunuz.

2.) Yeni Veritabanı - Yeni bir veritabanı oluşturabilir ve veriyi ona geçirebilirsiniz . Boş veritabanını ve tüm anahtarlarını, dizinlerini, nesnelerini, işlemlerini, işlevlerini vb. Kodlamanız ve ardından verileri ona aktarmanız gerekir. Bunun için komut dosyaları yazabilir veya Red Gate'den SQL Data Compare gibi bir araç veya benzer araçlara sahip diğer satıcıları kullanabilirsiniz. Bu senin yanında daha fazla kurulum çalışması, daha fazla geliştirme ve test etme ve ortamınıza bağlı olarak, kapalı kalma sürenizi de etkileyebilir ancak göz önünde bulundurmanız gereken bir seçenek olabilir.

Bir Veritabanını küçültmek zorunda kaldığımda Eğer bu benim ortamım olsaydı, veri dosyasında adil / ağır miktarda beyaz bir alan bırakmayı düşünüyorum, çünkü bir disk domuzu olmayı seviyorum ve gelecekteki / beklenmedik bir büyümeye hazırlanmayı seviyorum. Bu yüzden, eğer alanın çoğunluğunu yeni silersek, geri alan vermek sorun olmazdı, ama "ama bir daha asla büyümeyecek" diyenlere asla güvenmezdim ve hala biraz boşluk bırakıyordum . Büyük ihtimalle birlikte gideceğim rota ( iç çekiş)) daha küçük kapalı kalma süresi olan pencerelerim varsa ve boş bir DB oluşturma ve buna veri aktarmanın karmaşıklığına maruz kalmak istemiyorsam, küçültme yaklaşımıdır. Ben o aşamalı bir kaç kez küçültmek olur Yani endeksleri yeniden sonra ve (giderek daha küçük dosya boyutu seçerek. Ben dev ve istenilen boyutta benim testlere dayanmaktadır gerektiğini düşündüm kaç kere dayanarak) .. Sonra' kimseye veritabanımı küçültmediğimi asla söyleme ;-)


1
Bir yığıntan (özellikle de yığının ortasından) çok fazla veri sildiyseniz, bu alanı kümelenmiş bir dizin ekleyene kadar (umarım sonsuza kadar) geri alamayacağınıza özel bir durum ekleyeceğim: ve sonra kümelenmiş dizini (bir yığına geri döndürerek) bırakınız. Tabii eğer yığın düzenli olarak kesiliyorsa endişelenmeyin. Ama yine de bahsetmeye değer.
Jonathan Fite

Birisi NOTRUNCATE VE TRUNCATEONLY'in anlamını açıklayabilir mi, görünüşe göre bu sayfalar yeniden düzenlenmiyor ve bu nedenle indeks parçalanmasına neden olmuyor mu?
David Garcia,

4
  1. Veritabanımı nasıl daraltabilirim? Hangi dosyaları küçültürüm? : Dosyaları DBCC SHRINKFILEbahsettiğiniz komutla tek tek daraltabilirsiniz . Sunucunuza, veritabanınızın kaç dosyadan oluştuğuna bağlıdır. Basit bir veritabanında bir veritabanı dosyası ve bir işlem günlüğü dosyası bulunur.
  2. Bunu yaparken düşüncelerim neler olmalı?: küçültme dizin parçalanmanızı etkiler, 3. noktaya bakın. Ayrıca, veritabanı dosyasını mümkün olan en az boyutta küçültmek istemediğinizi unutmayın, çünkü gerçek dünyadaki bir ortamda yine de büyüyecek. Bu yüzden, (örneğin, 7 megabayt vermiş olduğunuz gibi) boyutu,% 10 -% 20 boş alan bırakacak şekilde ayarlamanızı sağlar, çünkü üretim ortamında yine de doldurulacaktır. bazı otomatik büyüme çevrimlerini bu şekilde korur. Bu yüzden gerçek sayının dikkatli bir şekilde hesaplanması gerekiyor. Ayrıca, yaptığınız "big space freeup" işlem günlüğü dosyasını DB dosyası içinde kazandığınız alandan daha fazla şişireceğini unutmayın. Ayrıca, yaşayabileceğiniz gerçek uzay kazancı matematiksel olarak beklediğinizden daha az olacaktır! Diyelim ki matematiksel olarak 12 gösteriyi serbest bıraktınız.
  3. Sonra bir şey yapmalı mıyım? : Daha önce de belirttiğim gibi, SHRINK'in değişimlerinin bir sonucu olarak parçalanmanın bozulduğu endeksleri yeniden düzenlemek istiyorsunuz. Sorgu istatistikleri hakkında özel bir şey yapmanız gerekiyorsa, yeterince deneyimlemedim.
  4. Ya büyük bir veritabanıysa? Daha küçük artışlarla küçültebilir miyim? SHRINK işlemi istediğiniz zaman kesilebilir ve daha sonra devam edebilirsiniz. Mümkünse çevrimdışı bir veritabanında gerçekleştirmenizi öneririm. Böldüğünde ve devam ederken aynı küçültme boyutunda ilerleyecekti. Teorik olarak, 7 megabayt yerine daha dar bir hedef boyutu belirleyerek daha küçük artışlarla küçülebilirsiniz, ancak bunu üretimde gerçekleştirirseniz, o zaman sadece bir adım verin. Gördüğünüz gibi endeks parçalanması ve olası işlem günlüğü büyümesi ile ilgili sorunlar var. Bu yüzden sadece bir kez bu üzerinden gitmek istiyorum.

Hepimiz biliyoruz ki, yine de düzenli olarak SHRINK yapmanın önerilmez. Muhtemelen bildiğiniz tüm uyarıları ve feragatnameleri dışarıda bırakmaya çalışıyorum. Yedekleyin ve mümkünse bunu evde yapmayın :)

Bonus: Çoğaltma ortamında bunu yayıncı veritabanında gerçekleştirirseniz, abone veritabanlarının küçülmesine neden olmaz (bu, Express sürümleri olduğundan boyut sorunu olabilir).

Sonunda, reindex betiğim:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor

Buradaki tek değişken, select seçerek elde edilebilecek 14'tür DB_ID('YourDBName')ve senaryo yalnızca dba. * Şemaındaki tablolarla ilgilendiğinizi varsayar.


2
Endeks yeniden oluşturma notu için DBREINDEX'in SQL 2005'te kullanımdan kaldırıldığına dikkat edin. İmleç içeren büyük betik yerine, sadece kullanabilirsiniz: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" Bu yardımcı birine yardımcı olur.
KISS

2

Veritabanlarının küçültülmesiyle ilgili tüm uyarıları duydunuz ve hepsi doğru. Endekslerinizi parçalayacaktır ve genel olarak veritabanınızı doldurur ve bir üretim sisteminde yapılmamalıdır.

Ancak, genellikle SSD sürücümdeki alan nedeniyle iş istasyonumdaki bir yedeği geri yüklerken haftalık olarak yapıyorum. Dikkat et, bu senaryoyu ben yazmadım ama yıllar önce buldum. Diğer veritabanlarında [250 GB], ihtiyaç duyduğum tabloları transfer edecek bir SSIS paketi oluşturdum ve daha sonra bu yeni endeks hissi için indeksleri yeniden yarattım.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
    ,[StartUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
    SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

    PRINT 'Start ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    EXEC (@sql)

    PRINT 'Done ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    SELECT @SizeMB = size / 128.
    FROM sysfiles
    WHERE NAME = @DBFileName

    SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

    SELECT [FileSize] = @SizeMB
        ,[UsedSpace] = @UsedMB
        ,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
    ,[EndUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

    ,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a

1

Aşağıdaki alıntı doğrudan Microsoft’a aittir (2008-2016 sürümleri için geçerlidir) ve bu DBCC SHRINKFILEkomutu ne zaman ve nasıl kullanmanız gerektiği konusunda rehberlik eder .

https://msdn.microsoft.com/en-us/library/ms189493.aspx

En İyi Uygulamalar

Bir dosyayı küçültmeyi planlarken aşağıdaki bilgileri göz önünde bulundurun:

  • Küçültme işlemi en çok, kesikli bir tablo veya bir damlalıklı tablo işlemi gibi çok fazla kullanılmayan alan oluşturan bir işlemden sonra etkilidir.
  • Çoğu veritabanı düzenli günlük işlemler için boş alan gerektirir. Bir veritabanını tekrar tekrar daraltırsanız ve veritabanı boyutunun yeniden arttığını fark ederseniz, bu, küçültülmüş alanın normal işlemler için gerekli olduğunu gösterir. Bu durumlarda, veritabanını tekrar tekrar küçültmek boşa harcanmış bir işlemdir.
  • Bir daralma işlemi, veritabanındaki dizinlerin parçalanma durumunu korumaz ve genellikle parçalanmayı bir dereceye kadar artırır. Bu, veritabanını tekrar tekrar daraltmamak için başka bir nedendir.
  • Aynı veritabanında aynı anda birden çok dosyayı sırayla daraltın. Sistem tablolarındaki çekişmeler blokaj nedeniyle gecikmelere neden olabilir.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.