目录

什么是事务日志

事务日志的组成

事务日志大小维护方法

Truncate

Shrink

索引碎片

总结

什么是事务日志

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

事务日志的组成

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

事务日志是一个循环文件。当数据库创建以后,逻辑日志从物理日志文件的起始位置开始。新的日志记录被添加到逻辑日志的后面直到物理日志文件的末尾。日志截取会把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 操作,我们也要按照实际情况决定是否需要重建/重组织索引。

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

SQL Server Transaction Log Truncate && Shrink的更多相关文章

  1. MS SQL错误:SQL Server failed with error code 0xc0000000 to spawn a thread to process a new login or connection. Check the SQL Server error log and the Windows event logs for information about possible related problems

          早晨宁波那边的IT人员打电话告知数据库无法访问了.其实我在早晨也发现Ignite监控下的宁波的数据库服务器出现了异常,但是当时正在检查查看其它服务器发过来的各类邮件,还没等到我去确认具体情 ...

  2. sql server 2000,Log.LDF文件丢失,附加数据库失败的解决办法[转]

    SQL Server数据库备份有两种方式,一种是使用BACKUP DATABASE将数据库文件备份出去,另外一种就是直接拷贝数据库文件mdf和日志文件ldf的方式.下面将主要讨论一下后者的备份与恢复. ...

  3. MySQL的redo log结构和SQL Server的log结构对比

    MySQL的redo log结构和SQL Server的log结构对比 innodb 存储引擎 mysql技术内幕 log buffer根据一定规则将内存中的log block刷写到磁盘,这个规则是 ...

  4. SQL Server如何截断(Truncate)和收缩(Shrink)事务日志

    当SQL Server截断事务日志时,它仅仅是在虚拟日志文件中做个标记,以便不再使用它,然后准备以重用形式来做备份(假如运载在完整或是批量日志恢复模型).也就是说,在使用简单恢复模型时,事务日志包括如 ...

  5. SQL Server删除log文件

    数据库文件太大 SQL Server用的久了,会发现备份文件越来越大,这个其实主要是log文件的增加,删掉log文件就可以了.不过操作之前最好还是有个完整备份的好. 分离数据库 分离数据库,勾选删除链 ...

  6. [转]sql server transaction

    本文转自: http://www.2cto.com/database/201208/146734.html sql事务(Transaction)用法介绍及回滚实例   事务(Transaction)是 ...

  7. SQL Server数据库log shipping 灾备(Part1 )

    1.概述 Log Shipping为SQL Server提供的数据库备份过程.它可以将数据库整个复制到另一台服务器上.在这种情况下,交易日志也会定期发送到备份服务器上供恢复数据使用,这使得服务器一直处 ...

  8. sql server 查询log日志 sql语句

    xp_readerrorlog 一共有7个参数: 1. 存档编号 2. 日志类型(1为SQL Server日志,2为SQL Agent日志) 3. 查询包含的字符串 4. 查询包含的字符串 5. Lo ...

  9. SQL Server数据库log shipping 灾备(Part2 )

    3.配置步骤: 主服务器(A机)设置 (1) 启用Log Shipping Configuration 右键单击需要配置日志传输的数据库->Tasks-> Ship Transaction ...

随机推荐

  1. uva10098 Generating Fast, Sorted Permutation

    #include"iostream"#include"stdio.h"#include"string.h"#include"alg ...

  2. hdu 最大报销额

    本题也是一个背包的问题,我觉得这道题的核心就是根据精确度将浮点型转化为整型然后利用动态规划进行求解,注意对题意的理解,有3种支票是不能够报销的. 我开始照着这个思路进行思考,但是敲出来的第一个代码居然 ...

  3. jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO

    描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较         ...

  4. HDU 1394 Minimum Inversion Number(线段树/树状数组求逆序数)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  5. Gitolite配置管理和GIT基本操作

    简述公司版gitolite的项目配置与管理 1. 基于秘钥对的管理 1.1 客户端(需要访问代码库的机器)生成秘钥对,采用RSA加密ssh-keygen -t rsa -f path_to_store ...

  6. ExtJS笔记2 Class System

    For the first time in its history, Ext JS went through a huge refactoring from the ground up with th ...

  7. javaWeb中servlet开发——过滤器

    servlet开发--过滤器(filter) servlet有三种,分为简单servlet.过滤器servlet.监听servlet 简单servlet是作为一种程序所必须的开发结构保存的,继承htt ...

  8. mysql-insert-返回主键id

    function gen_this_insert_id($insert) { GLOBAL $link; $insert .= ' SELECT LAST_INSERT_ID();'; if (mys ...

  9. Delphi 如何清除动态数组的内存?

    SetLength(glb_IndexConfig,); FreeAndNil(glb_IndexConfig);

  10. Android Studio 快捷键使用

    最近开始全面转向Android Studio开发了,经常要去查快捷键,索性汇总下,自己方便查找 IDE 按键    说明 F1 帮助 Alt(Option)+F1 查找文件所在目录位置 Alt(Opt ...