資料庫本體 600MB,記錄檔邏輯大小 33MB,但實體檔案佔用 2.8GB。嘗試 `SHRINK DATABASE`、`TRUNCATE LOG` 均無效。核心原因:**邏輯記錄截斷 (Truncate) 與物理檔案縮小 是兩碼事**,且記錄檔內部可能因長時間未備份、異常關機、大量交易導致虛擬記錄檔 (VLF) 狀態為「作用中」無法截斷。
⚠️ 僅限非生產環境或無法備份的極端情況。原理:寫入大量虛擬交易填滿記錄檔,迫使作用中 VLF 循環至開頭,再截斷尾端。
USE [YourDatabase]; -- 修改為目標資料庫
GO
DECLARE @LogicalFileName sysname = N'YourDatabase_log'; -- 修改為邏輯記錄檔名 (sp_helpfile 查詢)
DECLARE @TargetSizeMB INT = 100; -- 目標大小 (MB)
DECLARE @MaxMinutes INT = 10; -- 最大嘗試分鐘數
-- 1. 記錄原始大小
DECLARE @OriginalSize INT = (SELECT size FROM sys.database_files WHERE name = @LogicalFileName);
PRINT '原始大小: ' + CAST(@OriginalSize * 8 / 1024 AS VARCHAR) + ' MB';
-- 2. 嘗試直接縮小 (若 VLF 允許)
DBCC SHRINKFILE (@LogicalFileName, @TargetSizeMB);
-- 3. 若未達目標,執行虛擬交易包裝迴圈
IF (SELECT size FROM sys.database_files WHERE name = @LogicalFileName) * 8 / 1024 > @TargetSizeMB
BEGIN
CREATE TABLE #DummyTrans (DummyColumn CHAR(8000) NOT NULL);
DECLARE @StartTime DATETIME = GETDATE();
DECLARE @Counter INT;
DECLARE @TruncLog NVARCHAR(MAX) = N'BACKUP LOG [' + DB_NAME() + N'] WITH TRUNCATE_ONLY'; -- 簡單復原模式專用
WHILE @MaxMinutes > DATEDIFF(MI, @StartTime, GETDATE())
AND (SELECT size FROM sys.database_files WHERE name = @LogicalFileName) * 8 / 1024 > @TargetSizeMB
BEGIN
SET @Counter = 0;
WHILE @Counter < 50000 -- 安全上限
BEGIN
INSERT #DummyTrans VALUES ('Fill Log');
DELETE #DummyTrans;
SET @Counter += 1;
END
EXEC (@TruncLog); -- 截斷非作用中部分
DBCC SHRINKFILE (@LogicalFileName, @TargetSizeMB); -- 嘗試縮小
END
DROP TABLE #DummyTrans;
END
-- 4. 最終結果
DECLARE @FinalSizeMB INT = (SELECT size FROM sys.database_files WHERE name = @LogicalFileName) * 8 / 1024;
PRINT '最終大小: ' + CAST(@FinalSizeMB AS VARCHAR) + ' MB';
GO
記錄檔暴增 99% 歸因於**缺乏記錄備份**或**長時間交易阻塞截斷**。標準流程「完整備份 → 記錄備份 → SHRINKFILE」解決多數問題。本文腳本為緊急備案,生產環境請優先走標準流程並根因分析 `log_reuse_wait_desc`。