ฉันจะลดขนาดไฟล์ทั้งหมดอย่างรวดเร็วสำหรับฐานข้อมูลทั้งหมดได้อย่างไร


47

ใน SQL Server (2008 ในกรณีนี้) ฉันจะย่อขนาดไฟล์ทั้งหมดอย่างรวดเร็วทั้งบันทึกและข้อมูลสำหรับฐานข้อมูลทั้งหมดในอินสแตนซ์ได้อย่างไร ฉันสามารถผ่าน SSMS และคลิกขวาแต่ละครั้งและเลือกงาน -> ลดขนาด แต่ฉันกำลังมองหาบางสิ่งที่เร็วขึ้น

ฉันสคริปต์สคริปต์ "สร้างฐานข้อมูล" บางส่วนและลืมว่าพวกเขามีขนาดบอลลูนเป็นค่าเริ่มต้นและไม่ต้องการพื้นที่ที่สงวนไว้สำหรับไฟล์เหล่านี้ในโครงการนี้ค่อนข้างมาก

คำตอบ:


55

เมื่อคุณทำ "Tasks -> Shrink" จาก GUI DBCC SHRINKDATABASEคำสั่งนี้จะออกคำสั่งเบื้องหลัง ลองมัน. เมื่อกล่องโต้ตอบปรากฏขึ้นอย่าคลิกปุ่ม "ตกลง" คลิกปุ่ม "สคริปต์" แทน คุณจะเห็นคำสั่งในหน้าต่างแบบสอบถาม รวมกับแบบสอบถามบน sys.database (ออกจาก master และ msdb) และคุณสามารถสร้างสคริปต์เพื่อย่อขนาดฐานข้อมูลทั้งหมด

ตัวอย่างเช่น (นำมาจากความคิดเห็นของ 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;

คัดลอกผลลัพธ์ของแบบสอบถามนั้นและเรียกใช้เพื่อย่อขนาดไฟล์ทั้งหมดของคุณ


1
ตกลงฉันคิดว่าฉันมีสิ่งที่ฉันต้องการ (น่าเกลียด แต่ไม่เพียงแค่สิ่งที่ผมต้องไป) 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แต่การหาที่ให้ฉันเป็นปัญหาใหม่ ออกเพื่อโพสต์คำถามอื่น
jcolebrand

อย่างจริงจัง. ตรวจสอบคำตอบ @ Sandy sp_MSForEachDB (นอกจากนี้ยังมี "ตาราง" sproc ด้วย) จะมีประโยชน์มาก
swasheck

3
และนี่คือข้อเตือนใจที่จำเป็นสำหรับทุกคนที่กำลังอ่านสิ่งนี้: การหดฐานข้อมูลของคุณเป็นสิ่งที่อันตราย
Nick Chammas

1
กรองออฟไลน์ DB จะทำให้ดียิ่งขึ้น :-)
TiloBunt

1
เห็นด้วยกับ @TiloBunt เงื่อนไขทั้งหมดดีกว่าที่ WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro

23

แล้วคำสั่ง sql บรรทัดเดียวล่ะ?

โปรดอ่านนี้โพสต์บล็อกที่น่าสนใจมากก่อนที่จะดำเนินการคำสั่ง SQL ต่อไปนี้

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'

6
รหัสบรรทัดเดียวไม่จำเป็นต้องดีกว่าถ้ามันอาจทำงานไม่ถูกต้อง โปรดอ่านข้อความเหล่านี้เนื่องจาก sp_msforeachdb สามารถข้ามฐานข้อมูลและไม่เตือนคุณ: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/ …และmssqltips.com/sqlservertip/2201/…
Aaron Bertrand

15

DBCC SHRINKDB (และลูกพี่ลูกน้อง SHRINKFILE) นั้นช้ามากเพราะมีการประมวลผลเธรดเดี่ยวจำนวนมากที่เกิดขึ้นในรหัสนั้น

วิธีที่เร็วกว่ามากในการย่อขนาดไฟล์ฐานข้อมูลคือ:

  • จัดสรรกลุ่มไฟล์ใหม่ให้กับฐานข้อมูล
  • ทำให้กลุ่มไฟล์นี้มีขนาดใหญ่เท่าที่ควรจะเป็น (ใช้sp_spaceusedเพื่อพิจารณาว่ามีขนาดใหญ่แค่ไหน)
  • สร้างดัชนีทั้งหมดไปยังกลุ่มไฟล์ใหม่นี้
  • วางกลุ่มไฟล์เก่า

เนื่องจากการสร้างดัชนีใหม่นั้นขนานกันอย่างหนาแน่นเทคนิคนี้มักส่งผลให้ฐานข้อมูลหดตัวเร็วขึ้นมาก แน่นอนว่าคุณต้องมีพื้นที่เพิ่มเติมเล็กน้อยสำหรับกลุ่มไฟล์ใหม่ในขณะที่กระบวนการกำลังดำเนินอยู่ อย่างไรก็ตามคุณต้องการพื้นที่เพียงพอในกลุ่มไฟล์ใหม่เพื่อเก็บกลุ่มไฟล์ที่ใหญ่ที่สุดในอินสแตนซ์ (เนื่องจากคุณจะเรียกคืนพื้นที่ตามที่คุณไป)

เทคนิคนี้ยังมีประโยชน์เพิ่มเติมของการจัดเรียงข้อมูลดัชนีของคุณในกระบวนการ


คุณลืมส่วนสำคัญ การสร้างดัชนีใหม่จะไม่ย้ายสิ่งอื่นใดรวมถึงสิ่งต่าง ๆ เช่นกระบวนงานที่เก็บไว้มุมมองฟังก์ชั่นคำพ้องความหมายฮีป ฯลฯ ฯลฯ
Jeff Moden

และสิ่งเหล่านั้นไม่ใช้พื้นที่ว่างที่คุณควรใส่ใจ พวกเขาต้องอยู่ในกลุ่มไฟล์หลักเช่นกันคุณไม่สามารถเคลื่อนย้ายพวกเขาได้ (และไม่ควรทำ)
Thomas Kejser

13

ฉันปรับแต่งแบบสอบถามเล็กน้อยเพื่อย่อเฉพาะบันทึกตามที่ขอ:

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'

"ได้อย่างรวดเร็วหดไฟล์ทั้งหมดทั้งบันทึกและข้อมูล"
Dezso

2
ฉันกำลังมองหาสิ่งนี้และกำลังจะโพสต์สองครั้งเมื่อฉันเห็นคำตอบของคุณ ไม่ใช่คำตอบโดยตรง แต่มีความเกี่ยวข้องอย่างมากและตรงประเด็นสำหรับกรณีของฉัน
Gomibushi

2

รหัสด้านล่างรับรายการฐานข้อมูลที่ไม่ใช่ระบบตั้งค่าฐานข้อมูลเป็นแบบอ่านอย่างเดียวแล้วย่อขนาดไฟล์ ฉันได้เก็บรหัสนี้ไว้ในกล่อง SQL Server สองสามกล่องโดยใช้ SQL Agent Job ซึ่งพื้นที่มีปัญหาเสมอ ในคืนวันเสาร์ / อาทิตย์ทุกสัปดาห์จะเริ่มทำงานและลดขนาดฐานข้อมูลทั้งหมดภายในไม่กี่ชั่วโมง (ขึ้นอยู่กับขนาดของฐานข้อมูล)

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

0

ย่อขนาดไฟล์ล็อกทั้งหมดยกเว้น 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'

0

อันนี้ขยายคำตอบข้างต้นโดยใช้เคอร์เซอร์เพื่อวนซ้ำคำสั่ง SQL ทีละคำ มันไม่สั้นเท่ากับคำตอบของ Emrah แต่มันจะช่วยให้ตรรกะเพิ่มเติมภายในขณะที่ลูปภายในเคอร์เซอร์ ..

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

0

เราสามารถทำซ้ำSHRINKDBและSHRINKFILEสำหรับฐานข้อมูลทั้งหมดแบบไดนามิก:

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

คุณสามารถหารายละเอียดในบทความนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.