Bagaimana cara mengecilkan semua file dengan cepat untuk semua database?

47

Dalam SQL Server (2008 dalam hal ini) bagaimana saya bisa dengan cepat menyusutkan semua file, baik log dan data, untuk semua database pada contoh? Saya bisa melalui SSMS dan klik kanan masing-masing dan pilih Tugas -> Kecilkan, tapi saya sedang mencari sesuatu yang lebih cepat.

Saya membuat skrip beberapa "Buat database" dan lupa mereka telah menggelembungkan ukuran untuk default, dan tidak perlu cukup banyak ruang yang disediakan untuk file-file ini pada proyek ini.

jcolebrand
sumber

Jawaban:

55

Ketika Anda melakukan "Tugas -> Kecilkan" dari GUI itu sebenarnya mengeluarkan DBCC SHRINKDATABASEperintah di belakang layar. Cobalah. Ketika kotak dialog muncul, jangan klik tombol "OK". Sebagai gantinya, klik tombol "Script". Anda akan melihat perintah di jendela kueri. Gabungkan dengan kueri pada sys.databases (tinggalkan master dan msdb), dan Anda bisa membuat skrip untuk mengecilkan semua database.

Misalnya (diambil dari komentar jcolebrand):

SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4;

Salin output dari permintaan itu dan jalankan untuk mengecilkan semua file Anda.

Larry Coleman
sumber
1
Ok, saya pikir saya memiliki apa yang saya inginkan (jelek tapi hanya melakukan apa yang saya butuhkan) SELECT 'USE [' + d.name + N']' + CHAR(13) + CHAR(10) + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) FROM sys.master_files mf JOIN sys.databases d ON mf.database_id = d.database_id WHERE d.database_id > 4Tapi mencari tahu itu memberi saya masalah baru. Tidak aktif untuk mengirim pertanyaan lain.
jcolebrand
Serius. Lihat jawaban Sandy. sp_MSForEachDB (ada juga "tabel" sproc juga) sangat membantu
swasheck
3
Dan inilah pengingat wajib untuk semua orang yang membaca ini: Mengecilkan basis data Anda berbahaya.
Nick Chammas
1
menyaring Offline DB akan membuatnya lebih baik. :-)
TiloBunt
1
Setuju dengan @TiloBunt, seluruh kondisinya lebih baik karena WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro
23

Bagaimana dengan satu baris pernyataan sql?

Silahkan baca ini posting blog sangat menarik sebelum mengeksekusi pernyataan sql berikut.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
CoderHawk
sumber
6
Satu baris kode belum tentu lebih baik jika mungkin tidak berfungsi dengan benar. Harap baca juga posting ini, karena sp_msforeachdb dapat melewati basis data dan tidak memperingatkan Anda: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… dan mssqltips.com/sqlservertip/2201/…
Aaron Bertrand
15

DBCC SHRINKDB (dan sepupunya SHRINKFILE) sangat lambat, karena ada banyak sekali eksekusi berurutan yang terjadi dalam kode itu.

Cara yang jauh lebih cepat untuk mengecilkan file database adalah ini:

  • Alokasikan filegroup baru ke basis data
  • Jadikan filegroup ini sebesar yang seharusnya (gunakan sp_spaceuseduntuk menentukan seberapa besar)
  • Bangun kembali semua indeks ke filegroup baru ini
  • Jatuhkan filegroup lama

Karena indeks yang dibangun kembali paralel secara masif, teknik ini sering menghasilkan penyusutan database yang jauh lebih cepat. Tentu saja, itu mengharuskan Anda untuk memiliki sedikit ruang ekstra untuk grup file baru saat proses berlangsung. Namun, Anda hanya perlu ruang yang cukup di grup fileg baru untuk menampung grup fileg terbesar dalam instance (karena Anda akan memperoleh ruang saat Anda melanjutkan).

Teknik ini juga memiliki manfaat tambahan yaitu defragment indeks Anda dalam proses.

Thomas Kejser
sumber
Anda lupa bagian penting. Indeks pembangunan kembali tidak akan memindahkan apa pun termasuk hal-hal seperti prosedur tersimpan, tampilan, fungsi, sinonim, tumpukan, dll, dll.
Jeff Moden
Dan mereka tidak memakan tempat yang harus Anda pedulikan. Mereka HARUS berada di filegroup UTAMA juga, Anda tidak bisa benar-benar memindahkan mereka (dan Anda juga tidak harus)
Thomas Kejser
13

Saya menyetel sedikit pertanyaan untuk menyusutkan hanya LOG seperti yang diminta:

set nocount on  
SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4 and mf.type_desc = 'LOG'
Frankachela
sumber
"cepat menyusutkan semua file, baik log dan data"
dezso
2
Saya mencari ini, dan akan menggandakan pos ketika saya melihat jawaban Anda. Bukan jawaban langsung, tetapi SANGAT relevan dan tepat untuk kasus saya.
Gomibushi
2

Kode di bawah ini, dapatkan daftar basis data non sistem, atur basis data agar hanya dibaca dan kemudian perkecil file tersebut. Saya telah menyimpan kode ini di beberapa kotak SQL Server menggunakan SQL Agent Job, di mana ruang selalu menjadi masalah. Pada Sabtu malam / Minggu setiap minggu, itu mulai berjalan dan mengecilkan semua basis data dalam beberapa jam (tergantung pada ukuran basis data).

declare @db varchar(255)
declare c cursor for
select name from sys.databases where is_read_only=0 and state=0
  and name not in ('master','model','tempdb','msdb')
open c
fetch c into @db
while @@fetch_status=0
begin
  exec SP_dboption @db,'trunc. log on chkpt.','true' 
  DBCC shrinkdatabase (@db)
  fetch next from c into @db
end
close c
deallocate c
Muhammad Sharjeel Ahsan
sumber
0

Kecilkan semua file log kecuali master, model, msdb:

EXEC sp_MSforeachdb '
DECLARE @sqlcommand nvarchar (500)
IF ''?'' NOT IN (''master'', ''model'', ''msdb'')
BEGIN
USE [?]
SELECT @sqlcommand = ''DBCC SHRINKFILE (N'''''' + 
name
FROM [sys].[database_files]
WHERE type_desc = ''LOG''
SELECT @sqlcommand = @sqlcommand + '''''' , 0)''
EXEC sp_executesql @sqlcommand
END'
Emrah Saglam
sumber
0

Yang ini memperluas jawaban di atas, menggunakan kursor untuk beralih melalui pernyataan SQL satu per satu. Ini tidak sesingkat jawaban Emrah tetapi memungkinkan untuk logika tambahan dalam loop sementara di dalam kursor ..

SELECT 
    'USE [' 
    + databases.name + N']' 
    + CHAR(13) 
    + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' 
    + masterFiles.name 
    + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) 
    + CHAR(10) 
    + CHAR(13) 
    + CHAR(10)                                                                  AS sqlCommand
INTO
    #shrinkCommands
FROM 
    [sys].[master_files] masterFiles 
    INNER JOIN [sys].[databases] databases ON masterFiles.database_id = databases.database_id 
WHERE 
    databases.database_id > 4; -- Exclude system DBs


DECLARE iterationCursor CURSOR

FOR
    SELECT 
        sqlCommand 
    FROM 
        #shrinkCommands

OPEN iterationCursor

DECLARE @sqlStatement varchar(max)

FETCH NEXT FROM iterationCursor INTO @sqlStatement

WHILE (@@FETCH_STATUS = 0)
BEGIN
    EXEC(@sqlStatement)
    FETCH NEXT FROM iterationCursor INTO @sqlStatement
END

-- Clean up
CLOSE iterationCursor
DEALLOCATE iterationCursor
DROP TABLE #shrinkCommands
Alistair
sumber
0

Kami dapat mengulangi SHRINKDBdan SHRINKFILEuntuk semua basis data secara dinamis:

while @DBID<=@MaxDBID
begin
  -- Used Dynamic SQL for all databases.
  Set @SQL ='Use '+@DBName+ ' '+Char(10)
  Set @SQL += 'DBCC SHRINKFILE('+@Filename+',5)' +Char(10)
  Set @SQL += 'DBCC SHRINKDATABASE('+@DBName+')'+Char(10)

  --#6 Increment DBid for looping over all databases
  Set @DBID = @DBID+1
  Select @DBName = DBName, @Filename=DBFileName from #DBNames where [dbid] = @DBID and type_Desc = 'LOG'
  Print (@SQL)
  Exec (@SQL)
end

Anda dapat menemukan detail di artikel ini .

Anup Kulkarni
sumber