常見痛點:資料檔 600 MB,記錄檔實際使用 33 MB,**配置大小卻達 2.8 GB**。`DBCC SHRINKFILE`、`BACKUP LOG ... TRUNCATE_ONLY` (已移除) 均無效。根因:**虛擬記錄檔 (VLF) 作用中部分位於檔案末端**,導致縮減無法釋放空間。
SET NOCOUNT ON;
DECLARE @LogicalFileName SYSNAME = N'MyDB_Log'; -- 邏輯檔案名 (sys.master_files.name)
DECLARE @TargetSizeMB INT = 512; -- 目標大小 (MB)
DECLARE @MaxMinutes INT = 10; -- 最大嘗試分鐘數
-- 1. 確認目前大小
DECLARE @CurrentSizeMB INT;
SELECT @CurrentSizeMB = size * 8 / 1024
FROM sys.master_files
WHERE database_id = DB_ID() AND name = @LogicalFileName;
PRINT 'Current Log Size: ' + CAST(@CurrentSizeMB AS VARCHAR(10)) + ' MB';
IF @CurrentSizeMB <= @TargetSizeMB
BEGIN
PRINT 'Already <= target size. No action needed.';
RETURN;
END
-- 2. 完整復原模式:先執行記錄備份 (截斷非作用中 VLF)
IF (SELECT recovery_model_desc FROM sys.databases WHERE name = DB_NAME()) = 'FULL'
BEGIN
DECLARE @BackupPath NVARCHAR(500) = N'D:\Backup\' + DB_NAME() + '_Log_' + REPLACE(CONVERT(VARCHAR(19), GETDATE(), 126), ':', '') + '.trn';
BACKUP LOG @LogicalFileName TO DISK = @BackupPath WITH COMPRESSION, CHECKSUM;
PRINT 'Log backup taken: ' + @BackupPath;
END
-- 3. 嘗試直接縮減
DBCC SHRINKFILE (@LogicalFileName, @TargetSizeMB);
-- 4. 若仍過大,迴圈製造虛擬交易推進 VLF 循環 (最後手段)
DECLARE @StartTime DATETIME = GETDATE();
DECLARE @Counter INT, @DummyTableName SYSNAME = N'##ShrinkLogDummy_' + CAST(@@SPID AS VARCHAR(10));
CREATE TABLE #Dummy (col CHAR(8000) NOT NULL); -- 每列 ~8KB,快速填滿 VLF
WHILE (SELECT size * 8 / 1024 FROM sys.master_files WHERE database_id = DB_ID() AND name = @LogicalFileName) > @TargetSizeMB
AND DATEDIFF(MI, @StartTime, GETDATE()) < @MaxMinutes
BEGIN
-- 批次寫入/刪除推進記錄檔指標
SET @Counter = 0;
WHILE @Counter < 1000
BEGIN
INSERT #Dummy VALUES (REPLICATE('X', 8000));
DELETE #Dummy;
SET @Counter += 1;
END
-- 簡單復原模式可直接 TRUNCATE;完整模式需再次記錄備份
IF (SELECT recovery_model_desc FROM sys.databases WHERE name = DB_NAME()) = 'SIMPLE'
DBCC SHRINKFILE (@LogicalFileName, @TargetSizeMB);
ELSE
BEGIN
BACKUP LOG @LogicalFileName TO DISK = @BackupPath WITH COMPRESSION, CHECKSUM;
DBCC SHRINKFILE (@LogicalFileName, @TargetSizeMB);
END
END
DROP TABLE #Dummy;
-- 5. 最終確認
DECLARE @FinalSizeMB INT;
SELECT @FinalSizeMB = size * 8 / 1024
FROM sys.master_files
WHERE database_id = DB_ID() AND name = @LogicalFileName;
PRINT 'Final Log Size: ' + CAST(@FinalSizeMB AS VARCHAR(10)) + ' MB';
SET NOCOUNT OFF;
| 步驟 | 原理 |
|---|---|
| 記錄備份 | 完整模式下唯一合法截斷 VLF 方式,將非作用中 VLF 標記可重用 |
| DBCC SHRINKFILE | 釋放檔案末端**連續可用 VLF** 空間,單位為 8KB 頁面 |
| 虛擬交易迴圈 | 大量 `INSERT/DELETE` 產生記錄,**推進記錄檔寫入指標** 循環至檔案開頭,使作用中 VLF 移離末端 |
| 臨時表 #Dummy | 單列 8KB,1000 迴圈 ≈ 8MB 記錄/輪,快速推進 |
| 時間上限 @MaxMinutes | 防止無限迴圈,生產環境建議 10-30 分鐘 |