(转)对SQLSERVER数据库事务日志的疑问

本文转载自桦仔的博客http://www.cnblogs.com/lyhabc/archive/2013/06/10/3130856.html

对SQLSERVER数据库事务日志的疑问

摸不透SQLSERVER了

实验环境:SQLSERVER2005 SP4,Windows7

本来没什么心情写文章,反正没人看,关于我文章中提到的问题,有些可以从文章结尾的MSDN补充那里找到答案,而有些还没有答案

根据CSDN博客的这篇文章介绍,大家可以先看一下,然后再继续往下看,因为下面会引用到CSDN博客里的一些内容

SQL Server事务日志介绍

第一个问题:为什麽我完整备份数据库的时候,为什麽事务日志记录数会增加的,再备份一次又减少,再备份一次又增加?

备份之后变成了100行记录

有时候不是固定会增加50行记录的,有时候当你再次备份的时候又会变回50行记录

而虚拟日志文件的数量会减少了,从原来的45个变成35个

备份之后

我是这样备份的

当我备份事务日志并截断日志之后,剩下10行记录,备份事务日志不会减少事务日志的物理大小,需要收缩事务日志才行

当我每次执行完整备份之后,log  space used都会增大

1 DBCC SQLPERF(LOGSPACE)

还有根据我上面提供的文章《SQLSERVER事务日志介绍》

当SQL Server把虚拟日志文件1和2作为可重用区域时,事务日志也相应被截断(Truncate)

需要注意的是,物理日志大小也会随着变动。如果数据库运行在完整或是批量日志恢复模型下,那么从LSN45到49之间的区域将被删除(delete),

而且直到事务日志被备份后,这段区域的空间才会被重用。

但是刚才也备份过事务日志并截断日志,但是log space used跟日志文件物理大小没有改变

SQLSERVER应该会以虚拟日志文件作为单位,如果某个虚拟日志文件里没有任何LSN了,那么截断事务日志会把

没有任何LSN的虚拟日志文件那部分里面的LSN删除

这里说一下截断重用

截断:如果执行了备份事务日志并截断日志的操作,那么这部分虚拟日志文件里的LSN日志记录会被删除,但是整个事务日志文件的物理大小不会变小

重用:你需要执行备份事务日志并截断日志的操作,这部分虚拟日志文件才会重用,这样就不用增加事务日志文件的大小

就是说,你要备份事务日志并截断日志,然后那些被删除了LSN日志记录的虚拟日志文件才能重用,但是SQLSERVER会不会删除虚拟日志文件呢?

MSDN并没有说到,MSDN只是说SQLSERVER会创建并扩展虚拟日志文件,但是没有提到会自动删除虚拟日志文件

重用回以前的空间,反复循环使用。

问题二:但是每个虚拟日志文件装载多少个LSN,这里我也不知道,有可能是随机的?

而重用的时候SQLSERVER应该不会不连续的

比如 像下面的情况

LSN  LSN  LSN  LSN  LSN  LSN  LSN -》

1       2       3    10      5      6      7

LSN 1、2、3都归属于一个虚拟日志文件A

LSN 5、6、7都归属于另一个虚拟日志文件B

LSN 10 归属于一个虚拟日志文件C

由于虚拟日志文件C里的LSN没有被删除,那么重用日志的时候就会跳过LSN 10 然后继续重用日志,但是我觉得SQLSERVER不会是这样的

我觉得SQLSERVER重用日志应该是下面这样的

LSN LSN LSN LSN LSN LSN LSN -》

1     2    3     4     5     6    7

一直连续下去,不会出现中间有些虚拟日志文件没有删除的情况,确保LSN序列的顺序性

我备份了事务日志之后,并截断之后,物理大小跟使用空间都没有变化

----------------------------------------------------------------------------------------------------------

第一个LSN:倒数第二个checkpoint之后的第一个LSN

最后一个LSN:最后一个checkpoint之前的那个LSN

检查点LSN:跟第一个LSN是一样的

完整LSN:跟第一个LSN是一样的

上面这个图是我还原数据库的时候的界面,大家可以先备份一下数据库,然后还原数据库,看一下还原的备份集是不是你刚刚备份的时候的一样

很简单的画了一张图

----------------------------------------------------------------------------------------------------------------

1 DBCC LOG([DLGPOS])

在这里说一下事务日志里的 operation字段,operation字段说明这个LSN是做什么操作的

例如:LOP_BEGIN_CKPT,CKPT:checkpoint,如果看到operation是LOP_BEGIN_CKPT,表明这个LSN在做checkpoint操作

因为备份数据库的时候,SQLSERVER会做checkpoint,所以你会看到第一个LSN会跟LOP_BEGIN_CKPT操作的那个LSN联系起来

把16进制翻译成10进制跟还原数据库的时候的第一个LSN是一样的

而Current LSN只是显示当前每个日志记录的LSN号码,没有特别的意思,所以昨天我说的,currentLSN等于第一个LSN是错的

-------------------------------------------------------------------------------------------------------

还有一个“位置”的东东, POSITION字段跟还原数据库的时候的位置是一一对应的,当我每完整备份一次数据库就会增加一,或者备份事务日志一次就会增加一

但是完整备份跟事务日志备份是分开的,看下图

1  USE [msdb]
2 GO
3 SELECT  [backup_set_id], [backup_finish_date], [database_name], [first_lsn],
4         last_lsn, [checkpoint_lsn], [is_copy_only],[position]
5 FROM    [dbo].[backupset] WHERE [database_name]=‘dlgpos‘
6 ORDER BY [backup_finish_date]

问题3:但是为什麽从64突然又回到9呢?为什麽会断裂呢?这个我还不搞不清楚,这个位置字段有什么用呢?

参考的文章:

http://msdn.microsoft.com/zh-cn/library/ms190925.aspx

http://msdn.microsoft.com/zh-cn/library/ms189085(v=SQL.90).aspx

http://msdn.microsoft.com/zh-cn/library/ms179355(v=SQL.105).aspx

---------------------------------------------------------------------------------------------------

MSDN补充来的

在上面的一篇参考文章里

事务日志物理体系结构

我摘抄重要部分吧

SQL Server 数据库引擎在内部将每一物理日志文件分成多个虚拟日志文件。虚拟日志文件没有固定大小,且物理日志文件所包含的虚拟日志文件数不固定。数据库引擎在创建或扩展虚拟日志文件时动态选择虚拟日志文件的大小。数据库引擎尝试维护少量的虚拟日志文件。在扩展虚拟日志文件后,虚拟日志文件的大小是现有日志大小和新文件增量大小之和。管理员不能配置或设置虚拟日志文件的大小或数量。

只有当日志文件使用较小的 size 和 growth_increment 值定义时,虚拟日志文件才会影响系统性能。如果这些日志文件由于许多微小增量而增长到很大,则它们将具有很多虚拟日志文件。这会降低数据库启动以及日志备份和还原操作的速度。建议您为日志文件分配一个接近于最终所需大小的 size 值,并且还要分配一个相对较大的 growth_increment 值

事务日志是一种回绕的文件

看一下这幅图

问题4:而minLSN有没有可能跟第一个LSN是一样的呢?而第一个LSN有没有可能跟minLSN处于相同的位置或者比第一个LSN排在后面?

我觉得有可能的,就像<SQLSERVER事务日志介绍>里面,假定LSN48是一个checkpoint,那么minLSN就排在第一个LSN后面

为什麽LSN50是一个minLSN呢?

根据msdn说的,minLSN是界定截断日志的边界点

minLSN前面的是日志记录是可以截断的,minLSN后面的日志记录是不可以截断的

-----------------------------------------------------------------------------------------------------------------

更正一下今天说的,无论你进行完整备份还是差异备份还是日志备份,事务日志文件里的所有日志都会保存到bak文件里

不管你进行多少次数据库备份、还原,这些事务日志都不会消失,收缩事务日志文件也不行的

除非你进行备份事务日志并截断日志

所以就不存在只保存到checkpoint的那部分,而是当你执行备份命令的时候,最后的那个LSN也会保存到bak文件里!!!!!!!

不信的话,你可以在完整备份数据库前执行下面的SQL语句,备份完毕之后再执行一下,看事务日志记录是不是一样的

1 USE [AdventureWorks]
2 GO
3 DBCC LOG([AdventureWorks])

还有截断事务日志,看一下前后是否一样

MSDN上说物理日志文件,逻辑日志文件,虚拟日志文件,LSN,checkpoint应该像下图这样

-----------------------------------------------------------------------------------------------------------------

很反感国内某些书本照抄MSDN的内容,当说到事务日志的时候就照抄MSDN,本来MSDN就说得很笼统

只能对它们说一句“他妈的”

由于文档以及相关文章实在太少,我也研究不下去了,连MSDN论坛里的rmaio大侠都说文档很少

关于fn_dblog的用法,没有什么人能够给出,只是说微软没有公开

http://social.msdn.microsoft.com/Forums/zh-CN/sqlserverzhchs/thread/271b9073-61c5-4049-b918-6ab5dbb26d3e

http://social.msdn.microsoft.com/Forums/zh-CN/sqlserverzhchs/thread/19546d80-6cf7-449c-bacd-421a1d32ab5f

-------------------------------------------------------------------------------------------------------

20130611补充

msdn文章:事务日志体系结构和管理

这个第一个日志记录的日志序列号 (LSN),称为最小恢复 LSN (MinLSN)

那么究竟是不是第一个LSN就是minLSN呢?我们做一个实验

先运行下面语句

1 USE [GPOSDB] --需要查看minLSN日志信息的数据库
2 GO
3 --DBCC LOG与[fn_dblog]的记录数是一样的,只是[fn_dblog]比DBCC LOG更加详细
4 SELECT * FROM [sys].[fn_dblog](NULL,NULL)
5 DBCC LOG([GPOSDB])

然后执行一次完整数据库备份

1 BACKUP DATABASE [GPOSDB] TO DISK=‘D:\GPOSDBFULLBACKUP20130611.BAK‘ 

你会发现备份之前跟备份之后的minLSN不同了,而且看下图

就是说  minLSN = 第一个LSN

我把fn_dblog的结果做了一下调整,还有更多有意思的东西

1 SELECT * INTO ##TDBLOG FROM SYS.[fn_dblog](NULL,NULL)
2 SELECT  * FROM [##TDBLOG]
3 SELECT  [Current LSN], [Operation], [Checkpoint Begin], [Checkpoint End],
4         [Minimum LSN], [Dirty Pages], [SPID], [Transaction Name],
5         [Description]
6 FROM    [##TDBLOG] ORDER BY [Current LSN] ASC

上图说明了,第一个LSN和最后一个LSN在两个checkpoint中间的,注意operation :LOP_BEGIN_CKPT和 LOP_END_CKPT

checkpoint的时候,有7个脏页写到磁盘里去

大家再执行一下下面这个语句

1 SELECT  [Current LSN], [Operation] ,[Transaction ID]
2         [Minimum LSN], [Dirty Pages], [SPID], [Transaction Name],
3         [Description]
4 FROM    [##TDBLOG] ORDER BY [Current LSN] ASC

大家注意看,我在SSMS里执行backup database的查询窗口的spid是59,SQLSERVER是先做checkpoint,然后再做backup database的操作的

我是怎麽知道,fn_dblog输出的结果对应于哪个数据库呢?

因为刚开始使用这个函数,不知道怎麽指定输出的某个数据库的日志信息,而这个函数有一个字段是[Database Name],但是这个字段输出都是NULL

然后我通过观察SPID这个字段,发现其中某一行有数据库启动的信息,因为我在查询窗口里指定了如下sql语句,use AdventureWorks,

再看一下SQL ERROR LOG,真的是SPID20这个进程启动的数据库,然后我use 其他数据库,发现也是一样的

所以你要看某一个数据库的日志信息的时候先要 use 你要查看日志的那个数据库

1 USE [AdventureWorks]
2 GO

----------------------------------------------------------------------------------------------------------------------------------

关于问题3,其实这个“位置”就是指的是“日志链

日志链
连续的日志备份序列称为“日志链”。 日志链从数据库的完整备份开始。 通常,仅当第一次备份数据库时,或者将恢复模式从简单恢复模式切换到完整恢复模式或大容量日志恢复模式之后,才会开始一个新的日志链。 除非在创建完整数据库备份时选择覆盖现有备份集,否则现有的日志链将保持不变。 在该日志链保持不变的情况下,便可从介质集中的任何完整数据库备份还原数据库,然后再还原相应恢复点之前的所有后续日志备份。 恢复点可以是上次日志备份的结尾,也可以是任何日志备份中的特定恢复点。 有关详细信息,请参阅事务日志备份 (SQL Server)。
若要将数据库还原到故障点,必须保证日志链是完整的。 也就是说,事务日志备份的连续序列必须能够延续到故障点。 此日志序列的开始位置取决于您所还原的数据备份类型:数据库备份、部分备份或文件备份。 对于数据库备份或部分备份,日志备份序列必须从数据库备份或部分备份的结尾处开始延续。 对于一组文件备份,日志备份序列必须从整组文件备份的开头开始延续。 有关详细信息,请参阅应用事务日志备份 (SQL Server)。

因为我的电脑里安装了yoursqldba,他会自动每天自动执行事务日志备份跟完整备份的job,所以就形成了这个日志链了

-----------------------------------------------------------------------------------------------------------------

补充:其实checkpoint也属于一个日志记录,图片应该像下面这样

minLSN:可以看到,最新的LSN是148,147是CheckPoint,在这个CheckPoint之前事务1已经完成,而事务2还未完成,

所以对应的MinLSN应该是事务2的开始,也就是142.

而从MinLSN到日志的逻辑结尾处,则称为活动日志(Active Log)。

-----------------------------------------------------------------------------------------------

根据园子里的careyson大侠说的,第一个问题

为什麽完整备份之后日志记录会增加,有时候备份完之后会增加,有时候备份完之后会减少

要说这个问题,大家要先看一下这篇文章:SQL Server 2008 存储结构之DCM、BCM

里面说到数据库有一个系统页面DCM页,这个页面记录了一个文件中的哪一个区在最新一次完整数据库备份以后被修改过

我们做一个实验,先做一次完整数据库备份,然后再做一次完整数据库备份,两次完整数据库备份之间,你都不要对数据库做任何操作

然后在SSMS里输入下面SQL语句

1 DBCC TRACEON(3604,-1)
2 DBCC PAGE([DLGPOS],1,6,3) --实际上是第7页

你会看到就算你没有对数据库做任何操作,但是数据库里的某些数据页依然也会被修改

但是究竟修改了多少数据,没有人知道,但是可以肯定的是SQLSERVER修改了一些数据,以至于在完整备份之后事务日志有所增加或减少

而在日志记录里会看到

LOP_SET_BITS->LCX_DIFF_MAP  位图

LOP_FILE_HDR_MODIFY->LCX_FILE_HEADER  数据库文件头部

LOP_MODIFY_ROW->LCX_BOOT_PAGE_CKPT  数据库启动页

以上这些都是数据库系统页的修改

如果对DCM页不是很理解可以看一下careyson里的文章

差异备份依靠一个BitMap进行维护,一个Bit对应一个区,自上次完整备份后,被修改的区会被置为1,

而BitMap中被置为1对应的区会被差异备份所备份。而到下一次完整备份后,BitMap中所有的Bit都会被重置为0。

http://www.cnblogs.com/CareySon/archive/2012/02/17/2355200.html#2702773

还有事务日志里有很多 LOP_LOCK_XACT->LCX_NULL ,估计这些操作是用来锁住系统保留页面的吧

-------------------------------------------------------------------------------------------------

时间: 2024-09-30 20:08:46

(转)对SQLSERVER数据库事务日志的疑问的相关文章

配置了AlwaysOn的数据库事务日志收缩

由于配置了AlwaysOn的数据库为完整恢复模式,使得数据库的事务日志增长飞快,导致报错“事务日志已满”. 解决方法: 1 完整备份事务日志,选中截断事务日志选项* 2 收缩数据库事务日志文件* 3 完整备份数据库 4 再次备份事务日志,同选中截断事务日志选项 5 再次收缩数据库事务日志文件 步骤1与2是否可省略待验证.

SQL Server数据库事务日志序列号(LSN)介绍

原文:http://blog.csdn.net/tjvictor/article/details/5251463 ? ? 日志序列编号(LSN)是事务日志里面每条记录的编号. 当你执行一次备份时,一些LSN值就被同时存储在文件本身及msdb..backupset表中.你可以使用RESTORE HEADERONLY语法来从备份文件中获取LSN值. ? 注意:在SQL Server 2000中,有一列叫做DifferentialBaseLSN.但在SQL Server 2005中,相同的列名称变成了

SQL Server数据库事务日志存储序列

原文 原文:http://blog.csdn.net/tjvictor/article/details/5251351 ? 如果你的数据库运行在完整或是批量日志恢复模式下,那么你就需要使用作业(job)来定期备份事务日志,保持你的事务文件大小处在一个可管理的范围.当你需要还原事务日志时,你就需要按照创建事务日志的顺序来恢复它们.你可以参考存在msdb..backupset表中的信息来确定还原文件的顺序,使用FirstLSN和LastLSN列的值作参考.当你备份时,这些备份信息就会存在backup

如何为你的数据库事务日志减肥?

在大多数SQL Server的工作环境中,尤其是在OLTP环境中,数据库的事务日志性能出现瓶颈时往往会导致事务完成需要更多的时间,此时许多人把原因都归结于I/O子系统,理由是它不能够支撑工作负载产生的的大量的事务日志,然而实际情况却都未必如此. 事务日志写等待时间 对 于事务日志来讲,写操作等待的时间可以使用sys.dm_id_virtual_file_stats和系统中的事件writelog等待进行监视.如果 写等待时间比你期望的I/O子系统较高,那麽I/O子系统就不能够支撑,这是一般的假设,

mssql 2000数据库事务日志清除

重点注意:在操作前一定要备份数据库-完整备份. 在进行操作前最好是先去查看下相关文章,在测试环境下测试,确定熟悉了之后 才在线上服务器进行操作(有个原则:新部署的一些应用,或者一些脚本,一定要在测试环境上先测试后才能拿到线上服务器应用或操作). 打开查询分析器: 1.执行: select fileid,groupid,name from sysfiles where groupid=0  //获取fileid,假设为2 2.执行: backup log winiis with no_log; d

(转)解释一下SQLSERVER事务日志记录

本文转载自桦仔的博客http://www.cnblogs.com/lyhabc/archive/2013/07/16/3194220.html 解释一下SQLSERVER事务日志记录 大家知道在完整恢复模式下,SQLSERVER会记录每个事务所做的操作,这些记录会存储在事务日志里,有些软件会利用事务日志来读取 操作记录恢复数据,例如:log explorer 那么事务日志记录怎麽查看,里面都记录了些什么? 打开可以利用下面SQL语句来查看所在数据库的事务日志记录 1 USE [GPOSDB] -

SQL Server中的事务日志管理(9/9):监控事务日志

当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会告诉你每个DBA应该知道的具体细节. 对于在我们关注下的所有数据库,在日志维护方面,我们的首要目标是最优化写性能,为了支持SQL Server写入日志的所有活动,包括数据修改,数据读取,索引维护等等.但是,留意下可能的日志碎片也是重要的,如前面文章介绍的,它会影响需要读取日志的过程性能,例如日志备份

SQLServer存储引擎——日志

3. SQLServer存储引擎之日志篇 (3.1)日志结构 (3.1.1)物理日志 (0)物理日志即数据库的.ldf文件, 当然后缀名是可以自定义的,默认是.ldf (1)一个SqlServer数据库,可以定义多个物理日志文件,SQL Server逻辑上把他们当作一个整体,顺序写入日志记录,用完第一个,再用下一个:即第一个日志文件的当前空间,如果没有可分配的VLF时,就会使用下一个日志文件的VLF,直到最后一个日志文件也没有可分配的VLF时,会重新回到第一个日志开始增长:VLF的使用如下图:

如何截断SQL Server2008+事务日志空间

SQL数据库事务日志记录数据库的任何更改,用户可回滚事务日志来恢复数据,但随着数据库使用时间变长,日志文件也会变得很大. 若要避免数据库的事务日志被填满,例行备份至关重要.做了日志备份后,会释放不活跃的VLF,增加日志的可用空间.但默认情况下备份日志,其日志文件的大小并未变化,如下图 备份前,总大小24.13MB 备份后,总大小仍然为24.13MB,但已用空间占比从93.1%降至11.0% 也就是,已使用日志空间是减小了,但未使用日志空间并未释放.其实,如果磁盘空间足够的话,可以不用收缩空间 那