一,找到每个数据库的日志文件大小
SQL Server:查看SQL日志文件大小命令:dbcc sqlperf(logspace)
DBA 日常管理工作中,很重要一项工作就是监视数据库文件大小,及日志文件大小。如果你管理数据库的有很多的话,每天一个一个数据库的去查看文件大小就太费神了,那就写个SQL脚本吧,放到 SQL Agent 中,每天自动去查看各个数据库文件及日志文件的大小,然后再通过数据库邮件,Email 到我们手中,岂不快哉!当然,可以把每天的记录存放到数据库中去,这样数据库及日志文件的增长趋势,我们也就一目了然了。
这里,介绍下获取数据库日志文件大小的方法。其实很简单,就是执行 SQL Server DBCC 命令:dbcc sqlperf(logspace)
dbcc sqlperf(logspace) 可以获取实例中每个数据库日志文件大小,及使用情况。如果要保存SQL日志文件大小,则需要先创建一个数据表,然后动态执行dbcc sqlperf(logspace)命令:
--创建数据库日志文件信息表 CREATE TABLE [Control].[DatabaseLogSize]( [dbname] [nvarchar](100) NULL, [dbid] [int] NULL, [log_logical_name] [nvarchar](100) NULL, [logsize] [decimal](30, 2) NULL, [logused] [decimal](30, 2) NULL, [status] [int] NULL ) ON [PRIMARY] GO --借助dbcc sqlperf(logspace)将数据插入上面新建的表 INSERT INTO [Control].[DatabaseLogSize]([dbname],[logsize],[logused],[status]) EXECUTE('dbcc sqlperf(logspace)')
之后我们在表[DatabaseLogSize]中就有了 [dbname]、[logsize]、[logused]、[status]四列数据了
二、将数每个数据库的日志文件逻辑名找出来
因为后面我们要使用DBCC SHRINKFILE命令执行日志收缩,这个命令必须提供数据库日志文件的逻辑名,所以现在我们要想办法将[DatabaseLogSize]表中的[log_logical_name]这一列值填上去,要找到数据库文件的日志逻辑名,首先要找到数据库的dbid。我们可以使用下面的语句找到[DatabaseLogSize]表中每个数据库的dbid:
SELECT dbid,name FROM master..sysdatabases WHERE [name] IN (SELECT [dbname] FROM [Control].[DatabaseLogSize])
使用Update语句更新[DatabaseLogSize]表的[dbid]列即可:
UPDATE [Control].[DatabaseLogSize] SET [dbid]=T_DB_ID.[dbid] FROM [Control].[DatabaseLogSize] INNER JOIN ( SELECT [dbid],[name] FROM master..sysdatabases ) AS T_DB_ID ON [DatabaseLogSize].[dbname]=T_DB_ID.[name]
这样[DatabaseLogSize]表的[dbid]列就有值了:
接下来我们可以通过下面的语句根据每个数据库的dbid来找到每个数据库日志文件的逻辑名称,在本例中因为我们的每个数据库只有一个日志文件所以每个数据库只会找到一个日志文件逻辑名,如果你的情况是有数据库有多个日志文件,那么有些数据库就会找出多个日志文件逻辑名。
SELECT name,database_id FROM sys.master_files WHERE database_id IN (SELECT [dbid] FROM [Control].[DatabaseLogSize]) AND type = 1--这里的1表示我们要找的是.ldf日志文件,如果你要找的是.mdf数据库文件将这里改为0即可
这里补充一个知识点:SQL Server中一个数据库虽然可以通过创建多个数据文件组(FileGroup)来存放不同的.mdf和.ndf数据文件,但是日志文件组一个数据库有且只能有一个,也就是说一个数据库的所有.ldf日志文件都只能属于一个文件组,在下图中我们可以看到在SQL Server的SMSS管理器中如果你新建的是一个.ldf日志文件,那么其文件组这一列显示的是不适用,说明我们无法将SQL Server的.ldf日志文件放到多个文件组中,SQL Server只允许每个数据库拥有一个日志文件组,所有该数据库的.ldf日志文件都放在这个默认的日志文件组中:
之后同样我们用Update更新[DatabaseLogSize]表的[log_logical_name]列即可:
UPDATE [Control].[DatabaseLogSize] SET [log_logical_name]=T_DB_LOGNAME.[name] FROM [Control].[DatabaseLogSize] INNER JOIN ( SELECT [name],database_id FROM sys.master_files WHERE type = 1 ) AS T_DB_LOGNAME ON [DatabaseLogSize].[dbid]=T_DB_LOGNAME.database_id
这样[DatabaseLogSize]表的[log_logical_name]列也就有值了:
三、收缩数据库日志文件
接下来我们就可以根据[DatabaseLogSize]表的值来收缩数据库日志文件了,这里我们使用循环判断如果[DatabaseLogSize]表中的数据库日志文件大小超过100MB了,我们就使用DBCC SHRINKFILE指令来收缩这个日志文件:
CREATE TABLE #LogNeedShrink ( [dbname] NVARCHAR(100) ,[log_logical_name] NVARCHAR(100) ) INSERT INTO #LogNeedShrink SELECT [dbname],[log_logical_name] FROM [Control].[DatabaseLogSize] WHERE [logsize]>100 --收缩超过100MB大小的日志文件 WHILE (SELECT COUNT(1) FROM #LogNeedShrink)>0 BEGIN DECLARE @CurrentDbName NVARCHAR(100) DECLARE @CurrentlogName NVARCHAR(100) SELECT TOP 1 @CurrentDbName=[dbname],@CurrentlogName=[log_logical_name] FROM #LogNeedShrink DECLARE @ShrinkScript NVARCHAR(1000); SET @ShrinkScript=N' USE '+QUOTENAME(@CurrentDbName,N'[')+N' DBCC SHRINKFILE (N'''+@CurrentlogName+N''' , 0, TRUNCATEONLY)' --这里告诉SQL Server将日志文件收缩为0,也就是让SQL Server能收缩多少就收缩多少 EXEC sp_sqlexec @ShrinkScript DELETE FROM #LogNeedShrink WHERE [dbname]=@CurrentDbName AND [log_logical_name]=@CurrentlogName END DROP TABLE #LogNeedShrink