如何查看被截断的日志

如果数据库做了日志备份操作,则日志会被截断,然后原来活动的VLF会被重用。使用sys.fn_dblog将会看不到任何被截断的日志。那如何查看日志备份中的日志呢?使用fn_dump_dblog读取日志备份的内容。它的输出和sys.fn_dblog是一样的,所以进行查询过滤时也可以跟其一样。

use master
go
backup log logtest to disk='d:\logtest.trn';
go
select [Current LSN], [Operation], [AllocUnitName], [Transaction Name]
from fn_dump_dblog (
NULL, NULL, 'DISK', 1, 'D:\logtest.trn',
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
where [Transaction ID]='0000:00000367'
go

当[Lock Infomation]的内容无用时

前面我们使用[Lock Infomation]的内容帮助我们定位和分析日志操作,但是如果数据操作没有单独锁定某个行时(e.g.锁升级和使用表提示锁定表),则它的内容对我们的帮助就很少了。

delete top(1) from demotable with (tablockx);

select [Current LSN], [Operation], [Transaction ID],
[AllocUnitName], [Page ID], [Slot ID], [Lock Information]
from fn_dblog(null, null)
where [transaction id]='0000:0000036a'

上面的删除使用tablockx表提示,使得删除是直接对表使用X锁,而不是行锁。这样在[Lock Information]就没有包含键锁的HASH值(Lockres)。如图,我们现在能获取到Page ID、Slot ID和Object ID,但是不能定位到行。

但是日志的有效工作负载还是包含了所有的内容,因此可以通过搜索[Log Record]或者 [RowLog Contents 0~5] 来找到具体的行。

最小化日志操作也会让查找日志变得更困难。最小化日志操作的日志内容只扫描了某个页包含了最小华日志操作,SQL Server必需保证它在事务提交前被刷新到磁盘。在相关日志中只看到LOP_FORMAT_PAGE操作及其操作(最小化日志操作)的Page ID。最小化日志只有INSERT、blob .WRITE和WRITETEXT/UPDATETEXT操作,其它的操作都会完整记录日志,这样分析日志要分析的内容就少了很多。有一种情况会增加操作的日志量:更新事务复制中的发布表的数据。

实践时的注意事项

本文的例子的日志量非常少,搜索起来也很快。在真实环境中可能要透过数百万行日志才能找到所需要的日志记录,当然会很慢。最好将sys.fn_dblog返回的日志行先存到表中,然后建立需要的索引,这样查询时会快很多。使用sys.fn_dblog时如果能传入开始和结束的LSN,也会让其它返回速度快一些。注意,如果传入不正确的LSN给sys.fn_dblog,则会导致服务器内核转储( server core dump ),在生产环境这会导致SQL Server僵死一会儿。

DDL 修改

分析DDL修改的思路跟分析数据修改的一样。数据库对象是存储于一个或多个系统表中的数据,所有DDL修改最终会通过修改系统表的数据而完成。这样会让所有的DDL修改在分析日志时看起来差不多,例如LOP_INSER_ROWS操作插入数据到sys.syschhobjs,它可能是CREATE TABLE,也可能是CREATE VIEW或者CREATE PROC,甚至CREATE TABLE foo和CREATE TABLE bar的日志看起来是一样的。

DDL操作和DML操作两者修改数据时的主要区别在于使用不同锁。DDL使用元数据锁(Metedata Lock),一般情况,DDL会以包含Object ID的SCH_M锁开始。

另外,分析日志中DDL,要与特定的版本和更新相匹配。不同的版本、SP甚至CU,元数据表和元数据表结构可能会不同。

利用OBJECT ID

找出某个对象的DDL具体操作的最好方法是通过找出在对象上请求SCH_M锁的事务。先通过OBJECT_ID()得对象的ID,然后在[Lock Information]列中匹配搜索模式N'%SCH%%'得到事务。通过事务再找到所有相关的操作日志。

--executed 2 DDLs: CREATE and ALTER
create table xx(id int ,val nchar(10));
insert into xx values(1,'A'),(2,'B')
alter table xx
alter column val nchar(20);
go
select OBJECT_ID('xx')
-- returned 293576084
go
select [Current LSN], Operation, [Lock Information], [Transaction ID], [Description]
from sys.fn_dblog(null,null)
where [Lock Information] like N'%SCH%293576084%'
go Current LSN Operation Lock Information Transaction ID Description
----------- ------------ ---------------------------------------------- -------------- -------------
00000023:000000a9:0002 LOP_LOCK_XACT HoBt 0:ACQUIRE_LOCK_SCH_M OBJECT: 7:293576084:0 0000:0000036b
00000023:000000b7:0002 LOP_LOCK_XACT HoBt 0:ACQUIRE_LOCK_SCH_M OBJECT: 7:293576084:0 0000:00000370

返回两个事务,我们逐一查看。

select [Current LSN], Operation, [AllocUnitName], [Lock Information], [Transaction ID],
[Description], [Begin Time], [Transaction Name], [Transaction SID]
from fn_dblog(null, null)
where [Transaction ID] = N'0000:0000036b';

从第一行LOP_BEGIN_XACT事务开始,在Description和Transaction Name看到CREATE TABLE,还有Begin Time,然后还有Transaction SID。由这些信息我们可以知道:谁什么时候创建了这个表。

余下的行结合System Base Tables可以解读出其含义:

  • LOP_INSERT_ROWS 插入 sys.sysschobjs

    这个操作是向sys.objects插入数据行。有4个LOP_INSERT_ROWS操作是因为sys.sysschobjs表有1个聚集索引和3个非聚集索引。

  • LOP_INSERT_ROWS 插入 sys.syscolpars

    这个操作向sys.columns插入2行数据。每一个插入操作有2条记录,分别为sys.syscolpars上的聚集索引和非聚集索引。

  • LOP_INSERT_ROWS 插入 sys.sysidxstats

    插入数据到sys.indexes。

  • LOP_INSERT_ROWS 插入 sys.sysiscols

    插入数据到sys.index_columns。

通过上面的分析,虽然没有得到具体的DDL语句,但是我们知道一些非常有用的信息:在2016/08/22 17:13:47:667 创建的表,表中有2列。如果我们进一步解析rowlog contents和log content还能知道列名。例子中的CREATE语句非常简单,如果是复杂的CREATE语句,会生成很多的日志记录。比如对表进行分区,则会增加很多LOP_INSERT_ROWS记录,因为每个分区必须往sys.sysrowstes添加行,分区上的每一个列和索引都必须被记录在sys.sysrscols中。而这些操作都需要在低级别的HoBT元数被插入前完成。

再来看看另一个事务:

select [Current LSN], Operation, [AllocUnitName],[Lock Information], [Transaction ID],
[Description], [Begin Time], [Transaction Name], [Transaction SID]
from fn_dblog(null, null)
where [Transaction ID] = N'0000:00000370'

从上面的日志可以看到这是个ALTER TABLE操作,并且操作是一个堆表,也能知道操作时间和SID。通过LOP_MODIFY_COLUMNS操作,知道这是修改列属性的操作。

查找被删除对象的OBJECT ID

对象被删除后,就没有办法根据OBEJCT ID去找相关日志了。但是我们知道删除对象本质上从sys.sysschobjs删除数据,所以搜索sys.sysschobjs的LOP_DELETE_ROWS操作。我们还知道操作的分配单元是sys.sysschobjs.clst。同时,被删除对象的名字肯定存在于Log Contents中的。

drop table xx;
go
select [Current LSN], Operation, [AllocUnitName], [Lock Information], [Transaction ID],
[Description], [Begin Time], [Transaction Name], [Transaction SID]
from fn_dblog(null, null)
where [Operation] = N'LOP_DELETE_ROWS'
and [AllocUnitName] = N'sys.sysschobjs.clst'
and CHARINDEX(cast(N'xx' as varbinary(4000)), [Log Record]) > 0;

根据找到的事务ID,去找到相关的日志记录:

select [Current LSN], Operation, [AllocUnitName], [Lock Information], [Transaction ID],
[Description], [Begin Time], [Transaction Name], [Transaction SID]
from fn_dblog(null, null)
where [Transaction ID] = N'0000:00000371';

从上在的日志很容易就知道谁什么时候删除的。注意在LOP_BEGIN_XACT后的LOP_LOCK_XACT,在它的锁信息里有被删除对象的OBJECT ID。有了OBJECT ID,我们就可以利它进一步的分析日志。

注意,OBJECT ID是能够被重用的。 所以在使用OBJECT ID分析日志时,要分辨出它是否被重用了。在日志中,LSN严格按照时间排序的,所以可以利用之来区分OBEJCT ID的重用。

还要注意CHARINDEX(cast(N'xx' as varbinary(4000)), [Log Record]) > 0,它可能会返回名字中包含‘xx’的其它对象。

分析日志不是一种常规的和常用的技术。同时,它的难度高,也很容易被海量的日志误导,所以分析时最好从多个角度,使用多种方法去定位相关的日志。

文中的例子,我用的SQL Server 2012 - 11.0.5343.0,同时dbo.xx表,我用是一个堆表。这两个地方导致与原文有较大差异。 BY Joe . TJ

如何解读SQL Server日志(3/3)的更多相关文章

  1. 如何解读SQL Server日志(2/3)

    接下来说说返回的RowLogo Content列,例子中返回了三个列.这些列包含了数据操作的"有效工作负载(Playload)"记录.根据不同操作类型有效负载的内容也是不同的,但是 ...

  2. 如何解读SQL Server日志(1/3)

    SQL Server 的事务日志包含所有数据修改的操作记录.分析日志一般作为解决某些问题的最后手段,如查看某些意外的修改.理解和分析日志内容是件非常困难的事情,fn_dblog通常会输出非常多的数据, ...

  3. 清理SQL Server日志释放文件空间的终极方法

    清理SQL Server日志释放文件空间的终极方法  转自:http://www.cnblogs.com/dudu/archive/2013/04/10/3011416.html [问题场景]有一个数 ...

  4. SQL Server日志文件庞大收缩方法(实测好用)

    原文:SQL Server日志文件庞大收缩方法(实测好用) 这两个命令连续执行,间隔时间越少越明显(可多次运行),直到达到效果 --截断 BACKUP LOG CloudMonitor TO DISK ...

  5. 收缩SQL Server日志不是那么简单

    收缩SQL Server日志不是那么简单的(翻译)   原文地址:http://rusanu.com/2012/07/27/how-to-shrink-the-sql-server-log/ 说明:本 ...

  6. SQL Server 日志和代理的错误日志

    本文介绍的日志不是事务日志,而是SQL Server 日志和代理的错误日志,按照主体把错误日志分为SQL Server.SQL Server Agent.Database Mail,以及 Window ...

  7. sql server 日志文件结构及误操作数据找回

    一. 概述 在sql server 里有数据文件.mdf和日志文件.ldf,日志文件是sqlserver数据库的另一个重要组成部分,日志文件记录了所有事务以及每个事务对数据库所做的修改.为了提高数据库 ...

  8. SQL Server日志文件过大 大日志文件清理方法 不分离数据库

    SQL Server日志文件过大    大日志文件清理方法 ,网上提供了很多分离数据库——〉删除日志文件-〉附加数据库 的方法,此方法风险太大,过程也比较久,有时候也会出现分离不成功的现象.下面的方式 ...

  9. 解决Sql Server 日志满了,设置收缩

    解决Sql Server 日志满了,设置收缩: --查看文件占用空间 . '文件大小(MB)',* from sysfiles; ALTER DATABASE SpyData SET RECOVERY ...

随机推荐

  1. RCP:拖拽功能的实现 Drag and Drop

    SWT中的拖拽是使用的org.eclipse.swt.dnd. 有三个需要密切注意的类: 1.DragSource 2.DropTarget 3.Transfer DragSource封装了需要被拖拽 ...

  2. ENode 1.0 - Staged Event-Driven Architecture思想的运用

    开源地址:https://github.com/tangxuehua/enode 上一篇文章,简单介绍了enode框架的command service api设计思路.本文介绍一下enode框架对St ...

  3. [.net 面向对象编程基础] (11) 面向对象三大特性——封装

    [.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...

  4. 常用的HTML5、CSS3新特性能力检测写法

    伴随着今年10月底HTML5标准版的发布,未来使用H5的场景会越来越多,这是令web开发者欢欣鼓舞的事情.然而有一个现实我们不得不看清,那就是IE系列浏览器还占有一大部分市场份额,以IE8.9为主,w ...

  5. java提高篇(二四)-----HashSet

          在前篇博文中(java提高篇(二三)-----HashMap)详细讲解了HashMap的实现过程,对于HashSet而言,它是基于HashMap来实现的,底层采用HashMap来保存元素. ...

  6. java那些小事---用偶数做判断,不要用基数做判断

          今天做项目遇到这样一个奇葩问题:我们先看如下代码: int ftcs = dealFtcs(ftcs); if(ftcs % 2 == 1){ //奇数 /* * 处理..... */ } ...

  7. Unity3D逻辑热更新,第二代舒爽解决方案,L#使用简介

    热更新 天下武功,无坚不破,唯快不破 热更新就是为了更快的把内容推到用户手中. 之前,我设计了C#Light,经过半年多的持续修补,勉强可用,磕磕绊绊.感谢那些,试过,骂过,用过的朋友,在你们的陪伴下 ...

  8. [翻译].NET随机数

    原文链接:http://csharpindepth.com/Articles/Chapter12/Random.aspx   随机数 当你在Stack Overflow上看到看到某个问题标题当中有“随 ...

  9. [安卓] 16、ListView和GridView结合显示单元实现自定义列表显示效果

    List在各种手机应用中都有体现,是安卓UI设计的必修课. 本文将介绍在开发中如何利用ListView和GridView设计自定义列表. 下面分别是用ListView和GridView做的效果: 上面 ...

  10. [FPGA] 1、开发板使用和引脚连接

    目录 1.注意事项 2.设备简介 3.引脚分配 注意事项: ① 插拔下载线时必须断电! ② Quartus II 软件和 NIOS 软件的版本必须一致,并安装在同一个目录下面,安装目录不要有中文和空格 ...