深入SQLServer日志收缩

问题背景

SQLServer的日志是DB级别的这点和MySQL不同,多个DB就需要维护多个日志文件并且每个DB的日志文件可以有多个,所以从空间资源的角度来说这给云上的用户带来一些困扰,毕竟在云上磁盘空间是要收费的,除了性能他们也非常关心这些日志何时截断重用、何时收缩

问题探讨

事务日志

在理解事务日志基本概念的基础上我们来做个有关收缩的测试:

    --1. 构建测试用的日志
    --  tpcc是我的测试DB,ITEM表是之前生成的一个测试表,这里不需要关心表内容
    USE [tpcc]
    GO
    DECLARE @VALUE INT
    SET @VALUE = 0
    WHILE @VALUE <= 100
    BEGIN
        SELECT * INTO ITEM_2 FROM ITEM
        DROP TABLE ITEM_2
        SET @VALUE = @VALUE + 1
    END
    GO  

    --2. 观察当前等待日志截断重用的原因和每个DB的日志使用量
    select log_reuse_wait_desc from sys.databases where name='tpcc'
    go
    dbcc sqlperf(logspace)
    go

    --3. 备份数据和日志
    BACKUP DATABASE TPCC TO DISK='D:\BACKUP\TPCC.BAK' WITH COMPRESSION,INIT
    BACKUP LOG TPCC TO DISK='D:\BACKUP\TPCC.TRN' WITH COMPRESSION,INIT

    --4. 再次观察当前等待日志截断重用的原因和每个DB的日志使用量
    select log_reuse_wait_desc from sys.databases where name='tpcc'
    go
    dbcc sqlperf(logspace)
    go

    --5. 收缩日志
    USE [tpcc]
    GO
    dbcc shrinkfile(log)

    --6. 查看收缩后的日志使用量
    dbcc sqlperf(logspace)
    go

这一步也可以通过上一步收缩的结果计算出来(90112*8K = 704 MB);

现在在理解基本概念的基础上产生了第一个疑问,为什么1G的日志使用了4%却只能收缩到704MB?

为了解答这个问题我们需要引入另一个概念 Virtual Log Files(VLF),SQLServer为了方便日志管理,逻辑上将事务日志划分为多个虚拟日志文件,我们要讨论的收缩就是以虚拟日志文件为单位操作的。

具体可以参考日志的结构

我们再来重复一次刚才的测试,这次加入对VLFs的记录观察;

在刚才的1、3、5步骤之后记录如下SQL返回结果,帮助后续分析;

USE [tpcc]
GO
dbcc loginfo

步骤1结束后

步骤3结束后

步骤5结束后

这里跟收缩日志最相关的是Stats字段,0表示inactive,2表示active,active状态的VLF通过checkpoint+日志备份可以转化为inactive,但有一个原则是header(可理解为最新的活动日志)部分只能后推或回绕(wraps around)不能move forward(跟offset相关);

在开始备份前有11个活动VLF,checkpoint(数据备份的第一阶段)+ 备份日志后只有最新的VLF处于活动状态(日志截断并标记老的VLF为inactive-可重用),收缩后释放掉了未使用的VLF;

截止到这里截断和收缩实际已经达到了充分利用空间的目的,虽然直观看物理文件没有下降多少但新的日志已经开始回绕;但即便如此一些客户还在追求物理文件的进一步减少,实际想达到这个目的也很简单,依据之前讲的header部分已经回绕,再次备份收缩就可以了;

--再次备份
backup database tpcc to disk='d:\backup\tpcc.bak' with compression,init
backup log tpcc to disk='d:\backup\tpcc.trn' with compression,init

--再次收缩
USE [tpcc]
GO
dbcc shrinkfile(log)    

--观察VLF
USE [tpcc]
GO
dbcc loginfo

为什么没有收缩最后一个inactive的VLF跟这个DB的日志初始化大小、shrinkfile的参数有关,简单说不回收最后一个VLF已经可以达到初始化的大小;

我们也可以通过VLF的总大小和物理文件对比做一个验证:

--通过FileSize计算要加8KB的页头                67043328+67043328+67043328+67043328+67043328+67043328+67043328+67559424+8192=536870912B=512MB

--通过最后一个偏移量算
469311488+67559424=536870912B=512MB

结论和建议

  • 日志截断依赖于checkpoint和日志备份(FULL模式)
  • 日志截断的含义是把VLF标记为可重用
  • 日志收缩的多少需要看VLF的header和VLF的数量以及大小而不是通过sqlperf返回的结果判断(这也是很多DBA和用户误解的地方)
  • VLF的数量是事务日志创建时初始化好的一个初始值后续会随日志增长和增加,大小跟日志文件的大小、增长速度相关没有恒等的计算方法
  • 在非云场景下(传统用户),不建议用户频繁做日志收缩去回收空间,因为这种收缩是有很大开销的,但肯定也不会一直增长,我们通过频繁的日志备份做截断、回绕日志文件以达到节省空间的目的;在云场景下(RDS),依然也不建议频繁收缩,但面对一些希望用其它资源换空间资源且业务场景允许的情况下,建议这部分用户使用OpenAPI定制化自己的备份策略
时间: 2024-08-30 14:03:35

深入SQLServer日志收缩的相关文章

清除SQLServer日志的两种方法

server|sqlserver 日志文件满而造成SQL数据库无法写入文件时,可用两种方法:一种方法:清空日志.1.打开查询分析器,输入命令DUMP TRANSACTION 数据库名 WITH NO_LOG2.再打开企业管理器--右键你要压缩的数据库--所有任务--收缩数据库--收缩文件--选择日志文件--在收缩方式里选择收缩至XXM,这里会给出一个允许收缩到的最小M数,直接输入这个数,确定就可以了. 另一种方法有一定的风险性,因为SQL SERVER的日志文件不是即时写入数据库主文件的,如处理

SQLServer日志清空语句(sql2000,sql2005,sql2008)_MsSql

SQL Server日志清空方法   在查询分析器中顺序执行以下三步,其中 databasename 为你的数据库文件名 sql2000日志清空 可以将jb51.ldf文件变得很小,方便备份数据库等,在sqlserver查询分析器中执行即可. 复制代码 代码如下: DUMP TRANSACTION [jb51] WITH NO_LOGBACKUP LOG [jb51] WITH NO_LOGDBCC SHRINKDATABASE([jb51]) 1.清空日志: DUMP TRANSACTION

SQLServer日志清空语句(sql2000,sql2005,sql2008)

SQL Server日志清空方法 在查询分析器中顺序执行以下三步,其中 databasename 为你的数据库文件名 sql2000日志清空 可以将jb51.ldf文件变得很小,方便备份数据库等,在sqlserver查询分析器中执行即可.复制代码 代码如下:DUMP TRANSACTION [jb51] WITH NO_LOGBACKUP LOG [jb51] WITH NO_LOGDBCC SHRINKDATABASE([jb51]) 1.清空日志: DUMP TRANSACTION [dat

SQLServer日志配置问题

 太多VLFs SQL Server数据库引擎在内部将每一物理日志文件分成多个虚拟日志文件,这样日志管理系统可以轻松的跟踪那些部分是可以被重用的.事务日志文件根据下面的公式决定生成多少个VLFs,不管是自动增长还是手动增长: Up to 1MB 2 VLFs, each roughly 1/2 of the total size 1MB to 64MB 4 VLFs, each roughly 1/4 of the total size 64MB to 1GB 8 VLFs, each roug

通过sqlserver日志恢复误删除的数据

原文:通过sqlserver日志恢复误删除的数据       如果你已经急的焦头烂额,看到这篇文章的时候,请你换个坐姿,深呼吸几次,静下心来将这篇文章读完,也许你的问题迎刃而解.     我遇到的情况是这样的,网站被植入木马,盗取了我的web.config文件,web.config文件里面的数据库连接字符串没有加密,而我的数据库远程连接又没有做IP限制,黑客通过数据库客户端连上我的数据库后,将所有的表都Delete掉了,所以大家一定要有一个好习惯将数据库连接字符串加密或者对远程访问数据库的IP作

SQL语句实现SQL Server 2000及Sql Server 2005日志收缩(批量)_MsSql

复制代码 代码如下: DECLARE @name VARCHAR(25) DECLARE @SQL VARCHAR(1000) DECLARE @logid INT DECLARE sysdatabase_name CURSOR FOR SELECT name FROM master.dbo.sysdatabases OPEN sysdatabase_name FETCH NEXT FROM sysdatabase_name INTO @name WHILE @@FETCH_STATUS = 0

SQL语句实现SQL Server 2000及Sql Server 2005日志收缩(批量)

复制代码 代码如下:DECLARE @name VARCHAR(25) DECLARE @SQL VARCHAR(1000) DECLARE @logid INT DECLARE sysdatabase_name CURSOR FOR SELECT name FROM master.dbo.sysdatabases OPEN sysdatabase_name FETCH NEXT FROM sysdatabase_name INTO @name WHILE @@FETCH_STATUS = 0

SQL Server 错误日志收缩(ERRORLOG)

一.基础知识 默认情况下,错误日志位于 : C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\LOG\ERRORLOG 和ERRORLOG.n 文件中.默认保留有7个 SQL Server 错误日志文件,分别是:ErrorLog,Errorlog.1-Errorlog.6 ,当前的错误日志(文件ErrorLog)没有扩展名.每当启动 SQL Server 实例时,将创建新的错误日志ErrorLog,并将之前的ErrorLog更名为ErrorL

sqlserver日志文件总结及充满处理

交易日志(Transaction logs)是数据库结构中非常重要但又经常被忽略的部分.由于它并不像数据库中的schema那样活跃,因此很少有人关注交易日志. 交易日志是针对数据库改变所做的记录,它可以记录针对数据库的任何操作,并将记录结果保存在独立的文件中.对于任何每一个交易过程,交易日志都有非常全面的记录,根据这些记录可以将数据文件恢复成交易前的状态.从交易动作开始,交易日志就处于记录状态,交易过程中对数据库的任何操作都在记录范围,直到用户点击提交或后退后才结束记录.每个数据库都拥有至少一个