海南护送服务网

SQL Server数据库日志文件收缩的实现示例

2026-04-06 22:13:02 浏览次数:2
详细信息

1. 查看日志文件大小

-- 查看所有数据库日志文件信息
SELECT 
    DB_NAME(database_id) AS [Database Name],
    name AS [Logical Name],
    type_desc AS [File Type],
    size/128.0 AS [Size in MB],
    CAST(size/128.0 AS DECIMAL(10,2)) - CAST(FILEPROPERTY(name, 'SpaceUsed')/128.0 AS DECIMAL(10,2)) AS [Free Space in MB],
    (CAST(FILEPROPERTY(name, 'SpaceUsed')/128.0 AS DECIMAL(10,2))/CAST(size/128.0 AS DECIMAL(10,2)))*100 AS [Used %]
FROM sys.master_files
WHERE type = 1;  -- 1表示日志文件,0表示数据文件

2. 检查日志使用情况

-- 查看特定数据库的日志使用情况
DBCC SQLPERF(LOGSPACE);

-- 查看日志空间详细信息
DBCC LOGINFO('YourDatabaseName');

3. 简单收缩方法

-- 方法1:直接收缩日志文件
USE YourDatabaseName;
DBCC SHRINKFILE (YourLogFileName, 100);  -- 收缩到100MB

4. 完整收缩流程(推荐)

-- 步骤1:切换恢复模式(如果需要)
ALTER DATABASE YourDatabaseName SET RECOVERY SIMPLE;
-- 注意:生产环境慎用,会破坏日志链

-- 步骤2:执行检查点(强制将脏页写入磁盘)
CHECKPOINT;

-- 步骤3:备份日志(如果是FULL/BULK_LOGGED模式)
BACKUP LOG YourDatabaseName TO DISK = 'D:\Backup\LogBackup.trn';

-- 步骤4:收缩日志文件
USE YourDatabaseName;
DBCC SHRINKFILE (YourLogFileName, 100);  -- 100MB为目标大小

-- 步骤5:恢复原恢复模式(如果修改过)
ALTER DATABASE YourDatabaseName SET RECOVERY FULL;

5. 自动化脚本

-- 自动化收缩过程
DECLARE @DatabaseName NVARCHAR(128) = 'YourDatabaseName';
DECLARE @LogFileName NVARCHAR(128);
DECLARE @TargetSizeMB INT = 100;  -- 目标大小

-- 获取日志文件名
SELECT @LogFileName = name 
FROM sys.master_files 
WHERE database_id = DB_ID(@DatabaseName) AND type = 1;

-- 生成收缩命令
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = '
USE [' + @DatabaseName + '];
ALTER DATABASE [' + @DatabaseName + '] SET RECOVERY SIMPLE;
CHECKPOINT;
DBCC SHRINKFILE (''' + @LogFileName + ''', ' + CAST(@TargetSizeMB AS NVARCHAR) + ');
ALTER DATABASE [' + @DatabaseName + '] SET RECOVERY FULL;
';

PRINT @SQL;
-- EXEC sp_executesql @SQL;

6. 定期维护脚本(使用游标处理所有数据库)

DECLARE @DBName NVARCHAR(128);
DECLARE @SQL NVARCHAR(MAX);

DECLARE db_cursor CURSOR FOR
SELECT name 
FROM sys.databases 
WHERE state = 0  -- 在线数据库
    AND name NOT IN ('master', 'model', 'msdb', 'tempdb')  -- 排除系统数据库
    AND recovery_model_desc = 'SIMPLE';  -- 只处理简单恢复模式

OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @DBName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 'USE [' + @DBName + '];
    DECLARE @LogFile NVARCHAR(128);
    SELECT @LogFile = name FROM sys.database_files WHERE type = 1;

    DBCC SHRINKFILE (@LogFile, 100);
    PRINT ''收缩完成: ' + @DBName + '''';

    EXEC sp_executesql @SQL;

    FETCH NEXT FROM db_cursor INTO @DBName;
END

CLOSE db_cursor;
DEALLOCATE db_cursor;

7. 通过PowerShell实现

# PowerShell脚本收缩日志文件
Import-Module SQLPS -DisableNameChecking

$ServerInstance = "YourServer\Instance"
$DatabaseName = "YourDatabase"

$SQL = @"
USE [$DatabaseName];
DBCC SHRINKFILE (N'YourLogFileName', 100);
"@

Invoke-Sqlcmd -ServerInstance $ServerInstance -Database "master" -Query $SQL

8. 注意事项和最佳实践

重要提示:

生产环境慎用:频繁收缩日志文件会导致文件碎片,影响性能 恢复模式 监控日志增长
-- 设置日志文件自动增长
ALTER DATABASE YourDatabaseName
MODIFY FILE (NAME = YourLogFileName, 
          MAXSIZE = 1024MB,  -- 最大限制
          FILEGROWTH = 64MB);  -- 每次增长大小

推荐做法:

定期维护

-- 创建维护计划
USE msdb;
EXEC sp_add_job @job_name = 'Log Maintenance';
-- 添加备份和收缩步骤

预防为主

紧急情况处理

-- 如果日志文件已满,可以尝试
USE master;
ALTER DATABASE YourDatabaseName SET EMERGENCY;
ALTER DATABASE YourDatabaseName SET SINGLE_USER;
DBCC CHECKDB (YourDatabaseName, REPAIR_ALLOW_DATA_LOSS);
ALTER DATABASE YourDatabaseName SET MULTI_USER;

常见问题解决:

-- 如果收缩无效,检查是否有活动事务
DBCC OPENTRAN('YourDatabaseName');

-- 查看当前事务
SELECT 
    session_id,
    transaction_id,
    name AS TransactionName,
    transaction_begin_time,
    transaction_type,
    transaction_state
FROM sys.dm_tran_active_transactions
WHERE database_id = DB_ID('YourDatabaseName');

选择合适的方法根据你的具体场景,生产环境建议先测试再执行。

相关推荐