SQL Server事务日志备份:测试尾日志是否紧随最近的已知日志备份


11

我们正在使用具有完全恢复模式的SQL Server。给定完整备份和一系列日志备份,我们希望能够检查从上次完整备份到当前尾日志的日志链是否完整。(实际上并没有还原这些备份;这里的目的是测试备份的一致性。)

我已经知道如何对现有备份执行此操作:使用RESTORE HEADERONLY,我可以获取每个文件的FirstLSN和LastLSN,可以对连续文件进行比较,以确定它们是否兼容。

但是,我不知道如何检查尾日志是否在上次日志备份之后。

如果我具有尾日志的FirstLSN,则可以将其与上一个日志备份的LastLSN进行比较。但是,如何获取尾部日志的FirstLSN?

我需要一个从SQL Server 2005向上运行的解决方案(最好使用t-sql)。到目前为止,我搜索Google均无济于事。顺便说一句。我首先将其发布在stackoverflow上。但是将其迁移到这里,因为它在此处被标记为脱位。

编辑

我在一个小示例(SQL Server 2005,9.0.5057)上尝试了两个提供的解决方案:

BACKUP DATABASE TestDb TO DISK = 'C:\temp\backup test\Full.bak' 

-- fire some update queries

BACKUP LOG TestDb TO DISK =  'C:\temp\backup test\Log1.bak' 

-- fire both queries from the provided answers: 
-- Martin Smith's answer yields: 838886656088920652852608
-- Shawn Melton's answer yields: 46000000267600001

RESTORE HEADERONLY FROM DISK = 'C:\temp\backup test\Log1.bak'  
-- yields: 46000000267600001

因此,似乎第一个偏离了几个数量级。

然后,我在SQL 2008 SP1(10.00.2531)上进行了相同的测试,其中两个查询均产生正确的答案。


我一直在做一些研究,因为这是一个有趣的问题,但是我并没有走太远。我不确定SQL是否开箱即用。
凯瑟琳·维尔雅德

1
我敢肯定,有一种方法可以验证这一点,也许使用LSN不能做到这一点。我会在几个小时内悬赏该问题,这个问题需要更多的见解

Answers:


12

我转到我的SQL Server 2008 Internals副本,并指出了DMV sys.database_recovery_status以查找下一个日志备份的第一个LSN。该列为last_log_backup_lsn您提供了BOL的选择:

最新日志备份的日志序列号。这是上一个日志备份的结束LSN和下一个日志备份的开始LSN。
NULL =不存在日志备份。数据库处于脱机状态,或者数据库将无法启动。

同样要提到的是,如果数据库处于SIMPLE恢复模式(自动截断模式)或不存在日志备份,则Kalen还会指出一个NULL值。

但是,如何获取尾部日志的FirstLSN?

如果不实际备份数据库的尾日志(没有测试实例可以尝试),则可以从逻辑上得出结论,提到的列中返回的值将是下一个日志备份的第一个LSN,在您的情况下是尾巴。

因此,执行以下操作将返回我相信您正在寻找的值:


SELECT 
   last_log_backup_lsn
FROM 
   sys.database_recovery_status
WHERE 
   databse_id = DB_ID('MyDb')

此DMV从SQL 2005开始可用。

编辑
除非您阅读了BOL链接,否则请注意,此DMV只会将值返回到在线数据库,或在BOL引用它时打开。如果发生故障,要求您对数据库进行尾日志备份,除非可以访问该数据库,否则您将无法通过上述代码来验证该值。如果失败,它可能不会。


该查询的结果似乎正确。
Andreas

对我来说当然是正确的。last_log_backup_lsn等于日志尾部的first_lsn。因此,如果您要使用Shawn的代码还原一个last_lsn等于last_log_backup_lsn的日志文件,那么您就知道备份到了尾日志为止。(当然,只有在查询时才保证是真的,下次可以开始新的日志备份。)
RLF 2013年

@RLF添加了一条附加注释,因为如果无法访问数据库,这也将是正确的。当需要实施灾难恢复计划时,它并不是真正可行的解决方案。纯粹用于桌面练习或测试您的计划。

6

应该执行以下操作。

WITH LSN_CTE
AS
(
SELECT TOP 1
       LEFT( LogRecords.[Current LSN], 8 )          AS Part1,
       SUBSTRING( LogRecords.[Current LSN], 10, 8 ) AS Part2,
       RIGHT( LogRecords.[Current LSN], 4 )         AS Part3
FROM   sys.fn_dblog(NULL,NULL) AS LogRecords
ORDER BY [Current LSN]
)
SELECT CAST( CAST( CONVERT( varbinary, Part1, 2 ) AS int ) AS varchar ) +
       RIGHT( '0000000000' + CAST( CAST( CONVERT( varbinary, Part2, 2 ) AS int ) AS varchar ), 10 ) +
       RIGHT( '00000'      + CAST( CAST( CONVERT( varbinary, Part3, 2 ) AS int ) AS varchar ), 5 ) AS [Converted LSN]
FROM   LSN_CTE

使用转换代码从十进制这篇文章

ORDER BY [Current LSN]可能完全是不必要的开销。我不确定。此功能的结果似乎总是按LSN顺序排列,我想它只是顺序读取日志,以防万一。


@MartinSmith:fn_dblog似乎没有很好的记录。我假设它的结果始终对当前数据库有效(因为WHERE DbName = 'XXX'代码段中没有)?
Andreas

@Andreas-是的,没有记录。是的,它从当前数据库的日志中返回信息。
马丁·史密斯

请参阅我对原始问题的编辑。您的代码段返回的数字比同一数据库的最近备份的LSN大得多。
Andreas

@Andreas-奇怪 我只在单个测试数据库上尝试过,它可以正常工作。不知道错误在哪里。您正在哪个版本的SQL Server上运行它?该CONVERT风格参数2可能是问题。
马丁·史密斯

(尽管无论如何,肖恩的回答似乎都比这个更可取)
马丁·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.