SQL Server Transaction Log Truncate && Shrink

目录

什么是事务日志算法

事务日志的组成数据库

事务日志大小维护方法post

Truncateui

Shrinkspa

索引碎片日志

总结code

什么是事务日志

  Transaction log   是对数据库管理系统执行的一系列动做的记录,并利用这些记录来保证在遭遇硬件故障,灾难状况下ACID的可用性。从物理上来讲,事务日志就是一个记录对数据库更新操做的文件。

事务日志的组成

SQL Server 数据库引擎在内部将每一个物理文件分为多个虚拟日志文件。虚拟日志文件没有固定大小和固定数量,这两个值是由数据库引擎动态决定的。blog

  事务日志是一个循环文件。当数据库建立之后,逻辑日志从物理日志文件的起始位置开始。新的日志记录被添加到逻辑日志的后面直到物理日志文件的末尾。日志截取会把LSN(Log Sequential Number)比最小恢复日志序列号(MinLSN)早的虚拟日志记录给释放掉。MinLSN 是要实现一次成功的数据库范围回滚所须要的最小日志记录。排序

事务日志的结构以下:索引

  每一个虚拟日志有多条记录组成,每条记录都有一个LSN(一条SQL 原子语句)。分析上面的图咱们能够看到虚拟日志1和2被截取了,这说明虚拟日志1和2中的事务已经成功提交(并不表明数据修改已经物理上被更新到数据库文件中,由于有一个涉及磁盘IO效率问题)。

  当逻辑日志到达物理日志文件的末尾之后,新的日志记录会循环到物理日志的开头位置,以下图所示:

  只要逻辑日志尾不超过逻辑日志头,这种循环就永远不会结束。若是旧的日志记录可以被周期性/频繁的截取,那么就会有足够的可用空间留给新添加的日志记录,这样整个物理日志文件大小就会保持在一个相对稳定的范围,反之则会出现如下两种状况之一:

  1. 若是设置了自动增加,则会按照增加百分比/值来增长物理日志文件大小,这就是为何咱们的事务日志文件常常会变得很大。
  2. 若是没有设置自动增加或者存储事务日志文件的磁盘没有可用空间了,那么SQL Server 会抛出9002 错误。

注意:若是一个数据库有多个事务日志文件(LDF), 那么除非第一个事务日志文件没有可用空间了,不然不会使用其余的事务日志文件。

事务日志大小维护方法

Truncate

  由上面的描述咱们能够大概知道Truncate 就是将事务日志中的能够回收的逻辑日志文件标识为能够再次使用,具体的触发条件分为两种状况:

  1. 对于Recovery Mode 为Simple 的数据库来讲,每次事务以后会自动执行CheckPoint 操做,将提交完的逻辑日志空间清空,以保证事务日志文件大小最小。这等同于事务日志中没有日志记录,那么能够理解成没有事务日志,一旦发生灾难,可能会致使数据丢失。
  2. 对于Recovery Mode 为Full/Bulked-Log 来讲,每次进行Backup Log 操做都会自动执行CheckPoint 操做,将提交完的逻辑日志空间清空。换句话说咱们能经过周期性的日志备份来维护事务日志文件大小的可控。

打开查询分析器,执行如下查询:

  

如今对数据库执行一第二天志备份, 而后执行LOGINFO命令:

  能够看到逻辑日志1,2的状态被标识为0,这意味着逻辑日志1和2均可以被重用了。可是咱们再观察下逻辑日志4的偏移和大小,这两个值并无变,也就意味着整个事务日志大小仍然为:

1384448+712704=2,097,152 字节(纯逻辑日志文件大小 + 8192字节头)

Shrink

  Shrink 便是收缩日志,Truncate 操做并不会改变整个事务日志文件大小,只会将本来活跃的逻辑日志标记为不活跃以供下次使用;

Shrink 操做会彻底破坏索引的物理结构,致使产生索引碎片,使索引失效。

为何会这样呢?由于数据文件收缩操做每次执行都会使用GAM 位图算法来找到文件中最大文件,而后将它尽量地移动到文件头,如此反复(相似冒泡排序)。这样就会彻底打乱聚簇索引的顺序,致使它由一个秩序进展的索引变成杂乱无章的索引。

对于DBCC SHRINKFILE, DBCC SHRINKDATABASE, 以及auto-shrink 它们都会产生同样的后果,引入索引碎片, 致使大量I/O操做,CPU 消耗以及事务日志的过载。

来看一个例子,先建立一个数据库:

USE MASTER;
GO 
IF DATABASEPROPERTYEX ('DBMaint2008', 'Version') > 0
DROP DATABASE DBMaint2008; 
CREATE DATABASE DBMaint2008;
GO
USE DBMaint2008;
GO 
SET NOCOUNT ON;
GO 
-- Create the 10MB filler table at the 'front' of the data file
CREATE TABLE FillerTable (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'filler');
GO 
-- Fill up the filler table
INSERT INTO FillerTable DEFAULT VALUES;
GO 1280 
-- Create the production table, which will be 'after' the filler table in the data file
CREATE TABLE ProdTable (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'production');
CREATE CLUSTERED INDEX prod_cl ON ProdTable (c1);
GO 
INSERT INTO ProdTable DEFAULT VALUES;
GO 1280 

 

 
  
而后查询索引碎片百分比:
-- check the fragmentation of the production table
SELECT [avg_fragmentation_in_percent] FROM sys.dm_db_index_physical_stats (
DB_ID ('DBMaint2008'), OBJECT_ID ('ProdTable'), 1, NULL, 'LIMITED');
GO 

 

经过上面截图能够发现初始状况下索引的碎片百分比仅0.5%, 这种状况已经很是好了。

咱们把刚才建立的表删掉并经过DBCC Shrink 操做回收空间:

能够看到索引碎片百分比已经接近100%,这样状况下索引不但不会为咱们查询数据提升效率,反而会加剧系统的负担。

索引碎片

SQL Server 提供了两种命令来处理上述状况:

a. Rebuild 索引

USE DBMaint2008;
GO
ALTER INDEX ALL ON ProdTable REBUILD
GO

 

b. Reorganize索引

USE DBMaint2008;
GO
ALTER INDEX ALL ON ProdTable REORGANIZE
GO 

 

咱们来看一下对上面索引碎片接近100%的表进行索引重组后的效果:

能够看到数据库表的索引恢复了正常,可是这种方案也不彻底推荐,对于数据量很大的聚簇索引来讲,重建/重组织索引会产生大量I/O, CPU 消耗,因此平时好好维护索引才是咱们应该作的。

总结

  1. Truncate 只会将虚拟日志的活跃部分变成非活跃部分,这样就能够重用这些空间,它并不会影响总体事务日志大小;对于Simple 数据库来讲每次事务结束后都会执行CheckPoint 检查,对于Full/Bulked-Log 数据库来讲每第二天志备份操做之后都会执行CheckPoint 检查。
  2. Shrink 操做能够减少日志文件的物理文件大小,同时也致使日志文件被从新组织,聚簇索引和非聚簇索引的原有结构都会被打乱,致使产生索引碎片,继而带来的影响是索引失效,磁盘I/O 和 CPU 的资源消耗加大,对于Shrink 咱们尽可能避免使用它,一旦无可奈何使用Shrink 操做,咱们也要按照实际状况决定是否须要重建/重组织索引。

  总之,使用周期性的日志备份来维护咱们的事务日志文件大小是很是明智的。

相关文章
相关标签/搜索