Saya Perlu Kecilkan Basis Data Saya - Saya baru saja membebaskan banyak ruang

35

Pertanyaan ini ditanyakan dalam berbagai bentuk di sini tetapi pertanyaannya bermuara pada:

Saya tahu menyusutkan database berisiko. Dalam hal ini, saya telah menghapus begitu banyak data dan saya tidak akan pernah menggunakannya lagi.

  • Bagaimana saya bisa mengecilkan basis data saya? File apa yang saya susutkan?
  • Apa yang harus saya pertimbangkan ketika melakukan ini?
  • Haruskah saya melakukan sesuatu setelahnya?
  • Bagaimana jika itu adalah database besar? Bisakah saya mengecilkannya dengan kenaikan kecil?
Mike Walsh
sumber
2
Saya bergumul dengan ini beberapa waktu yang lalu: dba.stackexchange.com/questions/47310/... Saya mencoba merangkum pengalaman saya dalam jawaban saya
Csaba Toth

Jawaban:

30

Beberapa Peringatan Awal:

  1. Secara umum dikenal sebagai praktik terburuk yang pernah menyusutkan database produksi atau file data (File log adalah masalah lain yang dibicarakan pertanyaan ini ). Saya menyarankan orang untuk tidak mengecilkan database mereka di posting blog seperti ini di mana saya berbicara tentang "ukuran yang tepat" dan perencanaan yang baik. Saya tidak sendirian di sana ( Paul Randal , Brent Ozar , hanya untuk menyediakan beberapa tautan lagi). Mengecilkan file data atau indeks fragmen basis data, lambat dan melelahkan sumber daya Anda, dapat menguras sistem Anda dan hanya merupakan hal yang buruk untuk dilakukan, umumnya
  2. Dalam hal ini, kita semua tahu risikonya ada, kita siap menghadapinya, tetapi kita membebaskan banyak ruang yang kita tahu tidak akan pernah kita butuhkan lagi. Jadi dalam kasus khusus ini - penyusutan sangat masuk akal sebagai salah satu opsi kami.

Jika Anda sudah membaca tentang kekhawatiran dan risiko dan Anda masih perlu melakukan psikiater ini karena Anda membebaskan signifikan jumlah ruang, mudah-mudahan sisa jawaban ini akan membantu Anda keluar. Tetapi pertimbangkan risikonya.

Ada dua pendekatan utama yang dipertimbangkan di sini:

1.) Kecilkan Ya, lakukan penyusutan yang sebenarnya - Pertimbangkan untuk menggunakan DBCC SHRINKFILEalih-alih DBCC SHRINKDATABASE, Anda memiliki kontrol lebih besar atas apa yang menyusut dan bagaimana. Ini pasti akan menyebabkan beberapa penurunan kinerja - ini adalah operasi besar yang melakukan banyak IO. Anda berpotensi lolos dengan penyusutan berulang ke ukuran target yang semakin kecil.

Ini adalah contoh "A.)" di DBCC SHRINKFILEtautan di atas .. Datafile sedang menyusut ke ukuran target 7MB dalam contoh ini. Format ini adalah cara yang baik untuk menyusut berulang kali sesuai dengan waktu jeda jendela Anda. Saya akan melakukan ini dalam pengujian pengembangan untuk melihat bagaimana kinerja terlihat dan seberapa rendah / tinggi Anda dapat meningkatkan dan untuk menentukan waktu yang diharapkan dalam produksi. Ini adalah operasi online - Anda dapat menjalankannya dengan pengguna dalam sistem mengakses database yang menyusut, tetapi akan ada penurunan kinerja, hampir dijamin. Jadi monitor dan tonton dan lihat apa yang Anda lakukan ke server, pilih jendela downtime atau periode aktivitas yang lebih ringan, idealnya.

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

Selalu Ingat: - setiap kali Anda mengecilkan Anda memecah indeks Anda dan harus melakukan indeks membangun kembali jika Anda akan mengecilkan potongan selama periode waktu yang lama. Anda sekarang dikenai biaya itu setiap kali jika Anda tidak bisa menyelesaikannya dalam satu jendela.

2.) Basis Data Baru - Anda dapat membuat basis data baru dan memigrasikan data ke dalamnya. Anda harus membuat skrip database kosong dan semua kunci, indeks, objek, procs, fungsi, dll. Dan kemudian memigrasikan data ke dalamnya. Anda bisa menulis skrip untuk ini atau Anda bisa menggunakan alat seperti SQL Data Compare dari Red Gate atau vendor lain dengan alat serupa. Ini lebih banyak pekerjaan pengaturan di sisi Anda, lebih banyak pengembangan dan pengujian, dan tergantung pada lingkungan Anda juga dapat meledakkan jendela downtime Anda juga tetapi pilihan untuk dipertimbangkan.

Ketika saya dipaksa untuk mengecilkan Database Jika ini adalah lingkungan saya, saya akan mencari untuk meninggalkan ruang putih yang adil / besar dalam file data karena saya suka menjadi babi disk dan suka dipersiapkan untuk pertumbuhan di masa depan / tak terduga. Jadi saya akan baik-baik saja memberikan ruang kembali jika kita hanya menghapus sebagian besar ruang, tetapi saya tidak akan pernah percaya orang mengatakan "tapi itu tidak akan pernah tumbuh lagi" dan masih meninggalkan beberapa ruang putih. Rute yang mungkin saya tempuh ( menghela nafas) adalah pendekatan menyusut jika saya memiliki jendela downtime yang lebih kecil dan tidak ingin menimbulkan kerumitan membuat DB kosong dan memigrasikan data ke dalamnya. Jadi saya akan mengecilkannya beberapa kali secara bertahap (berdasarkan berapa kali saya pikir saya perlu berdasarkan pengujian saya di dev dan ukuran yang diinginkan. Semakin memilih ukuran file yang lebih kecil) dan kemudian membangun kembali indeks .. Dan kemudian saya ' d tidak pernah memberi tahu siapa pun bahwa saya menyusutkan database saya ;-)

Mike Walsh
sumber
1
Saya akan menambahkan kasus khusus bahwa jika Anda menghapus banyak data dari tumpukan (terutama dari tengah tumpukan) Anda tidak akan bisa mendapatkan ruang itu kembali sampai Anda menambahkan indeks berkerumun ke dalamnya (semoga selamanya), dan kemudian jatuhkan indeks berkerumun setelah (mengubahnya kembali menjadi tumpukan). Tentu saja jika heap terpotong secara teratur maka tidak ada masalah. Namun masih layak disebut.
Jonathan Fite
Dapatkah seseorang menjelaskan implikasi NOTRUNCATE AND TRUNCATEONLY, ternyata yang terakhir tidak mengatur ulang halaman dan karenanya tidak menyebabkan fragmentasi indeks?
David Garcia
4
  1. Bagaimana saya bisa mengecilkan basis data saya? File apa yang saya susutkan? : Anda dapat mengecilkan file satu per satu dengan DBCC SHRINKFILEperintah yang Anda sebutkan. Tergantung pada server Anda, berapa banyak file yang terdiri dari basis data Anda. Database sederhana memiliki satu file database dan satu file log transaksi.
  2. Apa yang harus saya pertimbangkan ketika melakukan ini?: menyusut memengaruhi fragmentasi indeks Anda, lihat poin ke-3. Juga perhatikan bahwa Anda tidak ingin mengecilkan file database ke ukuran yang seminimal mungkin, karena di lingkungan dunia nyata itu akan tumbuh pula. Jadi saya akan menyetel ukurannya (dalam contoh Anda Anda memberikan 7 megabita) dengan cara yang Anda akan meninggalkan 10% -20% ruang kosong dalam file database, karena itu akan tetap diisi dalam lingkungan produksi, dan Anda dapat simpan beberapa siklus pertumbuhan otomatis seperti itu. Jadi jumlah aktual perlu perhitungan yang cermat. Perhatikan juga bahwa "pembebasan ruang besar" yang Anda lakukan akan menggembungkan file log transaksi lebih dari ruang yang Anda peroleh dalam file DB. Juga, perolehan ruang aktual yang mungkin Anda alami akan lebih kecil dari yang Anda harapkan secara matematis! Jadi katakanlah Anda secara matematis membebaskan 12 pertunjukan,
  3. Haruskah saya melakukan sesuatu setelahnya? : Seperti yang saya sebutkan sebelumnya, Anda ingin mengindeks ulang indeks yang fragmentasi terdistorsi sebagai akibat dari perubahan SHRINK. Saya belum cukup bereksperimen jika Anda perlu melakukan sesuatu yang istimewa tentang statistik kueri.
  4. Bagaimana jika itu adalah database besar? Bisakah saya mengecilkannya dalam peningkatan yang lebih kecil? Operasi SHRINK dapat diinterupsi kapan saja, dan Anda dapat melanjutkannya nanti. Saya akan menyarankan untuk melakukannya pada database offline jika memungkinkan. Dengan menyela dan mengkoneksi itu akan maju ukuran menyusut yang sama sekalipun. Secara teoritis Anda dapat menyusut dalam peningkatan yang lebih kecil dengan menentukan ukuran target yang kurang ketat daripada 7 megabyte, tetapi saya akan mengatakan bahwa jika Anda melakukan itu dalam produksi, maka cukup berikan satu langkah saja. Seperti yang Anda lihat ada masalah dengan fragmentasi indeks dan kemungkinan pertumbuhan log transaksi. Jadi saya akan membahas ini sekali saja.

Kita semua tahu bahwa tidak disarankan melakukan SHRINK secara teratur. Saya mencoba untuk mengabaikan semua peringatan dan penolakan yang mungkin Anda ketahui. Cadangkan, dan jangan lakukan ini di rumah jika memungkinkan :)

Bonus: dalam lingkungan replikasi jika Anda melakukan ini pada database penerbit, itu tidak akan menyebabkan basis data pelanggan menyusut (yang mungkin memiliki masalah ukuran karena mereka edisi Express).

Akhirnya, skrip pengindeksan ulang saya:

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

Satu-satunya variabel dalam ini adalah 14, yang dapat diperoleh dengan mengeluarkan pilih DB_ID('YourDBName'), dan skrip mengasumsikan bahwa Anda hanya tertarik pada tabel di skema dba. *.

Csaba Toth
sumber
2
Untuk indeks, buat kembali catatan bahwa DBREINDEX sudah tidak digunakan lagi di SQL 2005. Daripada skrip besar dengan kursor, Anda bisa menggunakan: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX SELURUH? BANGUN KEMBALI" Semoga ini bisa membantu seseorang.
KISS
2

Anda telah mendengar semua peringatan tentang penyusutan basis data dan semuanya benar. Ini akan memecah indeks Anda dan secara umum, membersihkan database Anda dan tidak boleh dilakukan pada sistem produksi.

Tapi, saya biasanya melakukannya setiap minggu ketika saya mengembalikan cadangan pada workstation saya karena ruang pada drive SSD saya. Pikiran Anda, saya tidak menulis skrip ini tetapi menemukannya bertahun-tahun yang lalu. Pada database lain [250 GB], saya membuat paket SSIS yang akan mentransfer tabel yang saya butuhkan dan kemudian membuat ulang indeks untuk indeks yang terasa begitu segar.

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
pengguna1207758
sumber
1

Kutipan di bawah ini langsung dari Microsoft (berlaku untuk versi 2008-2016), dan memberikan panduan tentang jika / kapan dan bagaimana Anda harus menggunakan DBCC SHRINKFILEperintah.

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

Praktik terbaik

Pertimbangkan informasi berikut ketika Anda berencana untuk mengecilkan file:

  • Operasi menyusut paling efektif setelah operasi yang menciptakan banyak ruang yang tidak digunakan, seperti tabel truncate atau operasi drop table.
  • Sebagian besar database membutuhkan ruang kosong untuk operasi sehari-hari. Jika Anda mengecilkan basis data berulang kali dan memperhatikan bahwa ukuran basis data tumbuh lagi, ini menunjukkan bahwa ruang yang menyusut diperlukan untuk operasi reguler. Dalam kasus ini, berulang kali menyusutkan database adalah operasi yang sia-sia.
  • Operasi penyusutan tidak mempertahankan status fragmentasi indeks dalam basis data, dan umumnya meningkatkan fragmentasi hingga taraf tertentu. Ini adalah alasan lain untuk tidak menyusutkan database berulang kali.
  • Kecilkan beberapa file dalam database yang sama secara berurutan, bukan secara bersamaan. Kontensi pada tabel sistem dapat menyebabkan penundaan karena pemblokiran.
server g2
sumber