欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

您真的理解了SQLSERVER的日志链了吗?

程序员文章站 2022-06-13 13:47:38
...

您真的理解了SQLSERVER的日志链了吗? 先感谢 宋沄剑 给本人指点迷津,还有 郭忠辉 童鞋今天在QQ群里抛出的问题 这个问题跟宋沄剑讨论了三天,再次感谢宋沄剑 一直以来,SQLSERVER提供了一个非常好的管理工具:SSMS 又因为这个管理工具太好了,所有操作的简

您真的理解了SQLSERVER的日志链了吗?

先感谢宋沄剑给本人指点迷津,还有郭忠辉童鞋今天在QQ群里抛出的问题

这个问题跟宋沄剑讨论了三天,再次感谢宋沄剑

一直以来,SQLSERVER提供了一个非常好的管理工具:SSMS

又因为这个管理工具太好了,所有操作的简单化,以至于使我们中毒太深

对于SQLSERVER内部的一些概念搞得不清不楚

比如这些概念:日志备份链,备份日志链,日志链,备份链,备份集

大部分都是由于SSMS的界面所导致,有时候有些问题做一下实验就可以验证了,偏偏我们信赖了GUI

阅读下文之前大家可以先看一下宋沄剑的文章

SQL Server CheckPoint的几个误区

再谈SQL Server中日志的的作用

SQL Server误区30日谈-Day20-破坏日志备份链之后,需要一个完整备份来重新开始日志链

先说清楚这些概念吧

SQLSERVER只有日志链,备份记录(有些人也叫备份链)本人觉得叫备份记录更合适

下面三个东西说的都是同一样东西

备份集=备份记录=备份链

备份集:比如备份的集合,比如有对一个数据库的完备1、差备、日备1、完备2、日备2,这些数据库的备份的集合就是备份集

不过我更喜欢叫备份记录

备份记录实际上指 SELECT * FROM [msdb].[dbo].[backupset]

截断日志跟日志链断裂是否是同一样东西?

截断日志跟日志链断裂不是同一样东西


什么是日志链

其实大家可以把bak文件理解成一个压缩包,完整备份差异备份的时候会把数据和日志一起带进压缩包,

日志备份的时候只会把日志带进压缩包

您真的理解了SQLSERVER的日志链了吗?

我们先从一个实验开始吧

测试环境:SQLSERVER2012 开发版

脚本

为了不产生额外的日志,所以脚本里面没有select into语句,本来想select into进去临时表再对临时表进行排序

但是因为select into会产生额外的日志,只有直接对fn_dblog进行排序了

创建数据库

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

1 USE master
2 GO
3 --创建数据库
4 CREATE DATABASE LogChainTest;
5 GO
6 --改为完整恢复模式
7 ALTER DATABASE LogChainTest SET RECOVERY FULL;
8 GO
View Code

查看当前的事务日志

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

1 USE [LogChainTest]
2 GO
3 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC
View Code

您真的理解了SQLSERVER的日志链了吗?

进行完整备份

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

1 --第一个完整备份
2 DECLARE @strbackup NVARCHAR(100)
3 --改为日期加时间的
4 SET @strbackup = 'C:\LogChainTest_full1_'
5     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
6                       ''), ':', '') + '.bak'
7 BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT,CHECKSUM ;
8 GO
View Code

查看bak文件中的事务日志

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 SELECT  *
 2 FROM    fn_dump_dblog(NULL, NULL, N'DISK', 1,
 3                       N'c:\LogChainTest_full1_20131206202536.bak', DEFAULT,
 4                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 5                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 6                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 7                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 8                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 9                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
10                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
11                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
12                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
13                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
14                       DEFAULT, DEFAULT)
View Code

您真的理解了SQLSERVER的日志链了吗?

我们再查看此时的数据库事务日志

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

1 USE [LogChainTest]
2 GO
3 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC
View Code

您真的理解了SQLSERVER的日志链了吗?

发现完整备份之后事务日志比之前少了69-10=59行

我们发现bak文件中只记录AllocUnitId,而不记录表名,可能因为bak文件里的日志给SQLSERVER还原用的

而不是给用户查看事务日志用的,所以SQLSERVER干脆不记录表名了,以节省备份时间

您真的理解了SQLSERVER的日志链了吗?

您真的理解了SQLSERVER的日志链了吗?

看到这里大家会有问题了,为什麽日志会截断了?完整备份之后事务日志比之前少了69-10=59行

这里只能说明SQLSERVER把一些跟本数据库无关紧要的日志截断了,例如创建数据库时候修改master数据库的表

而不能说完整备份可以截断日志

而paul的文章给出了解释:

If you switch recovery models to FULL or BULK_LOGGED, until you take the first full backup,

you are still essentially in the SIMPLE recovery model, and so the log will truncate on checkpoint.

文章地址:

http://www.sqlskills.com/blogs/paul/misconceptions-around-the-log-and-log-backups-how-to-convince-yourself/

问题:为什麽bak文件里的日志的最后的三条记录会是

LOP_BEGIN_CKPT

LOP_XACT_CKPT

LOP_END_CKPT

我们用下图来表示吧

您真的理解了SQLSERVER的日志链了吗?

这里大家可以看一下宋沄剑的文章:再谈SQL Server中日志的的作用

将CheckPoint标记写入日志(标记中包含当前数据库中活动的事务信息),并将Log Block写入持久化存储


我在开头说过事务日志中会放进去bak文件里,但是并不是整个事务日志文件里的日志记录全部放进去

而是把(1)已经checkpoint了的 (2)LAZY WRITTER (3)EAGER WRITTER

还是看宋沄剑的文章吧,这麽复杂的过程我就不概括了:再谈SQL Server中日志的的作用

还有paul的文章:

Debunking a couple of myths around full database backups(揭穿一系列数据库完备的误区)

More on how much transaction log a full backup includes(数据库完备包含了多少事务日志)

实际上checkpoint和数据库备份有着密切联系,备份的时候SQLSERVER需要将哪些数据存入去bak文件

而在备份期间所新生成的事务和变化的数据要不要存入bak文件,这里面比较复杂,就不详细说了

不过有一点要说的是:在数据库备份之前,数据库引擎会自动执行checkpoint,以便在备份中包含对数据库页的全部更改。

我摘抄了网上的一些资料

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 http://blog.csdn.net/tjvictor/article/details/5209604
 2 导致CheckPoint检查点的事件: 1.在数据库备份之前,数据库引擎会自动执行checkpoint,以便在备份中包含对数据库页的全部更改。
 3 
 4 2.日志的活动部分超出了服务器在 recovery interval 服务器配置选项中指定的时间内可以恢复的大小。
 5 
 6 3.日志的 70% 已满,并且数据库处于日志截断模式。
 7 
 8 当下列条件都为 TRUE 时,数据库就处于日志截断模式:数据库使用的是简单恢复模式,并且在执行上一条引用数据库的 BACKUP DATABASE 语句后,发生下列事件之一:
 9 
10 在数据库中执行一项最小日志记录大容量复制操作或一条最条小日志记录的 WRITETEXT 语句。
11 
12 执行一个在数据库中添加或删除文件的 ALTER DATABASE 语句。
13 
14 4.停止服务器也会在服务器上的每个数据库中发出一个检查点命令。下列停止 SQL Server 的方法将为每个数据库执行检查点:
15 
16 使用 SQL Server 配置管理器。
17 
18 使用 SQL Server Management Studio。
19 
20 使用 SHUTDOWN 语句。
21 --------------------------------------------------------------------------
22 http://www.cnblogs.com/CareySon/p/3315041.html
23 5.将恢复间隔设置为1分钟,意味着每1分钟会对所有的数据库做一次CheckPoint
24 
25     错误。将恢复间隔设置为1分钟不能想成建立一个Agent,每分钟写一个CheckPoint命令,这是两码事。这只是意味着每分钟去检查一次是否需要做CheckPoint,如果期间积累的日志量足够,才会对积累足够日志量的数据库去做CheckPoint。即使中间积累了巨量的日志,不到1分钟也不会做CheckPoint。
View Code

您真的理解了SQLSERVER的日志链了吗?

那么大家可以将bak文件里的事务日志当作为数据库事务日志

备份脚本

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 --创建数据库
 4 CREATE DATABASE LogChainTest;
 5 GO
 6 --改为完整恢复模式
 7 ALTER DATABASE LogChainTest SET RECOVERY FULL;
 8 GO
 9 
10 
11 
12 
13 
14 
15 --第一个完整备份
16 DECLARE @strbackup NVARCHAR(100)
17 --改为日期加时间的
18 SET @strbackup = 'C:\LogChainTest_full1_'
19     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
20                       ''), ':', '') + '.bak'
21 BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT,CHECKSUM ;
22 GO
23 
24 
25 
26 
27 
28 --第一个差异备份
29 USE LogChainTest
30 GO
31 CREATE TABLE tt(id INT)
32 INSERT INTO tt
33 SELECT 1
34 DECLARE @strbackup NVARCHAR(100)
35 --改为日期加时间的
36 SET @strbackup = 'C:\LogChainTest_diff_'
37     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
38                       ''), ':', '') + '.bak'
39 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL;
40 GO
41 
42 
43 
44 --第一个日志备份
45 USE LogChainTest
46 GO
47 INSERT INTO tt
48 SELECT 2
49 DECLARE @strbackup NVARCHAR(100)
50 --改为日期加时间的
51 SET @strbackup = 'C:\LogChainTest_log1_'
52     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
53                       ''), ':', '') + '.bak'
54 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
55 GO
56 
57 
58 
59 
60 --第二个完整备份
61 USE master
62 GO
63 DECLARE @strbackup NVARCHAR(100)
64 --改为日期加时间的
65 SET @strbackup = 'C:\LogChainTest_full2_'
66     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
67                       ''), ':', '') + '.bak'
68 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT;
69 GO
70 
71 
72 --第二个日志备份
73 USE LogChainTest
74 GO
75 INSERT INTO tt
76 SELECT 3
77 DECLARE @strbackup NVARCHAR(100)
78 --改为日期加时间的
79 SET @strbackup = 'C:\LogChainTest_log2_'
80     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
81                       ''), ':', '') + '.bak'
82 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
83 GO
View Code

备份策略:完整备份1-》差异备份-》日志备份1-》完整备份2-》日志备份2

还原脚本

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 --差异备份和日志备份1打乱
 2 USE master
 3 GO
 4 --还原第一个完整备份
 5 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131206230857.bak' 
 6 WITH REPLACE ,CHECKSUM, NORECOVERY
 7 GO
 8 
 9 --还原第一个日志备份
10 RESTORE LOG LogChainTest FROM DISK='c:\LogChainTest_diff_20131206230920.bak' 
11 WITH  NORECOVERY
12 GO 
13 
14 --还原差异备份
15 RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_diff_20131205222718.bak' 
16 WITH NORECOVERY
17 GO
18 
19 消息 3136,级别 16,状态 3,第 120 无法还原此差异备份,因为该数据库尚未还原到正确的早期状态。
21 消息 3013,级别 16,状态 1,第 122 RESTORE DATABASE 正在异常终止。
23 
24 
25 
26 
27 --还原第二个日志备份,没有报错
28 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log2_20131206230927.bak' 
29 WITH RECOVERY
30 GO 
31 
32 
33 
34 
35 --可以查询出id列有三行记录
36 USE [LogChainTest]
37 GO
38 SELECT * FROM [dbo].[tt]
View Code

上面的还原脚本,我先还原日志备份1,再还原差异备份结果就报错了

1 消息 3136,级别 16,状态 3,第 12 无法还原此差异备份,因为该数据库尚未还原到正确的早期状态。
3 消息 3013,级别 16,状态 1,第 14 RESTORE DATABASE 正在异常终止。

还有,为什麽不用还原完整备份2数据也没有丢失??

我们每次备份的时候,无论是完备、差备、日备都会把日志拷贝到bak文件里

而拷贝的时候会有一个last lsn确保日志顺序

您真的理解了SQLSERVER的日志链了吗?

当我先还原日志备份1,然后还原差异备份的时候因为last lsn的顺序不对所以就报错了

为什麽不用还原完整备份2数据也没有丢失??

这里先说一下完备、差备、日备的大概方式

完备:复制数据和少量的log到bak

差备:复制有差异的数据和少量的log到bak

日备:不复制数据,如果是第一次日备,会把所有的log复制到bak,如果是第二次日备,会把自上一次日备到这次日备的log复制到bak

paul的文章里有解释:

http://www.sqlskills.com/blogs/paul/misconceptions-around-the-log-and-log-backups-how-to-convince-yourself/

A log backup is *ALL* the log generated since the last log backup

备份策略:完整备份1-》差异备份-》日志备份1-》完整备份2-》日志备份2

我们没有还原完整备份2(相当于丢失了完整备份2),我们的还原顺序是

还原完整备份1(复制数据,根据redo/undo log保证事务一致性)

还原差异备份(复制差异数据,根据redo/undo log保证事务一致性)

还原日志备份1(数据全靠redo/undo log来恢复,根据redo/undo log保证事务一致性)

还原日志备份2(数据全靠redo/undo log来恢复,根据redo/undo log保证事务一致性)

因为日志备份2里面已经包含了从日志备份1到日志备份2的所有log,所以SQLSERVER可以凭借这些log来把数据恢复

而日志备份1里面已经包含了从完整备份1到日志备份1的所有log

所以,按理说,我们只需要还原完备1,日备1,日备2就可以恢复全部数据

测试:

我们使用下面备份脚本和还原脚本,看一下不还原日志备份1,直接还原日志备份2看有没有问题

备份脚本

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 --创建数据库
 4 CREATE DATABASE LogChainTest;
 5 GO
 6 --改为完整恢复模式
 7 ALTER DATABASE LogChainTest SET RECOVERY FULL;
 8 GO
 9 
10 
11 
12 
13 
14 
15 --第一个完整备份
16 DECLARE @strbackup NVARCHAR(100)
17 --改为日期加时间的
18 SET @strbackup = 'C:\LogChainTest_full1_'
19     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
20                       ''), ':', '') + '.bak'
21 BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT,CHECKSUM ;
22 GO
23 
24 
25 
26 
27 
28 --第一个差异备份
29 USE LogChainTest
30 GO
31 CREATE TABLE tt(id INT)
32 INSERT INTO tt
33 SELECT 1
34 DECLARE @strbackup NVARCHAR(100)
35 --改为日期加时间的
36 SET @strbackup = 'C:\LogChainTest_diff_'
37     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
38                       ''), ':', '') + '.bak'
39 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL;
40 GO
41 
42 
43 
44 --第一个日志备份
45 USE LogChainTest
46 GO
47 INSERT INTO tt
48 SELECT 2
49 DECLARE @strbackup NVARCHAR(100)
50 --改为日期加时间的
51 SET @strbackup = 'C:\LogChainTest_log1_'
52     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
53                       ''), ':', '') + '.bak'
54 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
55 GO
56 
57 
58 
59 
60 --第二个完整备份
61 USE LogChainTest
62 GO
63 INSERT INTO tt
64 SELECT 3 UNION ALL
65 SELECT 4
66 DECLARE @strbackup NVARCHAR(100)
67 --改为日期加时间的
68 SET @strbackup = 'C:\LogChainTest_full2_'
69     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
70                       ''), ':', '') + '.bak'
71 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT;
72 GO
73 
74 
75 --第二个日志备份
76 USE LogChainTest
77 GO
78 INSERT INTO tt
79 SELECT 5
80 DECLARE @strbackup NVARCHAR(100)
81 --改为日期加时间的
82 SET @strbackup = 'C:\LogChainTest_log2_'
83     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
84                       ''), ':', '') + '.bak'
85 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
86 GO
View Code

还原脚本

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 --还原第一个完整备份
 4 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131207102535.bak' 
 5 WITH REPLACE ,NORECOVERY
 6 GO
 7 
 8 
 9 --还原第二个日志备份
10 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log2_20131207102602.bak' 
11 WITH RECOVERY
12 GO 
View Code

您真的理解了SQLSERVER的日志链了吗?

您真的理解了SQLSERVER的日志链了吗?

插入的数据太少,日志太少,搞得文件的size不那么明显

结果报错

1 消息 4305,级别 16,状态 1,第 22 此备份集中的日志开始于 LSN 35000000017200001,该 LSN 太晚,无法应用到数据库。可以还原包含 LSN 35000000008600001 的较早的日志备份。
3 消息 3013,级别 16,状态 1,第 24 RESTORE LOG 正在异常终止。

因为没有还原日志备份1,缺少了完备1到日备1之间的日志,所以就报错了

我们使用下面的脚本来进行还原,只还原完备1,日备1,日备2

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 --还原第一个完整备份
 4 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131207102535.bak' 
 5 WITH REPLACE ,NORECOVERY
 6 GO
 7 
 8 --还原第一个日志备份
 9 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log1_20131207102542.bak' 
10 WITH NORECOVERY
11 GO 
12 
13 --还原第二个日志备份
14 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log2_20131207102602.bak' 
15 WITH RECOVERY
16 GO 
17 
18 USE [LogChainTest]
19 GO
20 SELECT * FROM tt
View Code

您真的理解了SQLSERVER的日志链了吗?

这次成功了,数据都没有丢失,那么说明我丢失了差异备份、完整备份2也没有关系

如果我丢失了日备1、差备、完备2,只有完备1和日备2,那么这个时候你只能祈祷了,你只能还原完备1

差备、日备1、完备2、日备2的数据都已经丢失


BAK文件中日志数量的多少

我刚才说

完备:复制数据和少量的log到bak

差备:复制有差异的数据和少量的log到bak

日备:不复制数据,如果是第一次日备,会把所有的log复制到bak,如果是第二次日备,会把自上一次日备到这次日备的log复制到bak

我怎麽看出来的?

测试:

我们看一下每次备份完毕后,bak文件里面的日志数量

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 SELECT  *
 4 FROM    fn_dump_dblog(NULL, NULL, N'DISK', 1,
 5                       N'c:\LogChainTest_full1_20131207102535.bak', DEFAULT,
 6                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 7                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 8                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
 9                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
10                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
11                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
12                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
13                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
14                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
15                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
16                       DEFAULT, DEFAULT)
View Code

完备1

您真的理解了SQLSERVER的日志链了吗?

差备

您真的理解了SQLSERVER的日志链了吗?

日备1

您真的理解了SQLSERVER的日志链了吗?

完备2

您真的理解了SQLSERVER的日志链了吗?

日备2

您真的理解了SQLSERVER的日志链了吗?

在完备2的时候bak中的日志只有44行,说明完整备份只存储一些必要的日志,不是所有日志都存储

完备存储这些日志的作用是在还原的时候根据这些log去redo/undo 保证事务一致性,所以只会写入少量日志

因为完备和差备都是复制数据,所以就没有必要像日备那样全部事务日志都复制到bak里面

而日备2为什麽只有73行记录,因为在日备1的时候SQLSERVER已经截断了事务日志,日备2的日志就像我前面说的

如果是第二次日备,会把自上一次日备到这次日备的log复制到bak

如果我们不想在backup log 的时候截断事务日志,可以使用NO_TRUNCATECOPY_ONLY这两个backup option

备份脚本 NO_TRUNCATE

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

  1 USE master
  2 GO
  3 --创建数据库
  4 CREATE DATABASE LogChainTest;
  5 GO
  6 --改为完整恢复模式
  7 ALTER DATABASE LogChainTest SET RECOVERY FULL;
  8 GO
  9 
 10 
 11 
 12 
 13 
 14 
 15 --第一个完整备份
 16 DECLARE @strbackup NVARCHAR(100)
 17 --改为日期加时间的
 18 SET @strbackup = 'C:\LogChainTest_full1_'
 19     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
 20                       ''), ':', '') + '.bak'
 21 BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT,CHECKSUM ;
 22 GO
 23 
 24 
 25 
 26 
 27 
 28 --第一个差异备份
 29 USE LogChainTest
 30 GO
 31 CREATE TABLE tt(id INT)
 32 INSERT INTO tt
 33 SELECT 1
 34 DECLARE @strbackup NVARCHAR(100)
 35 --改为日期加时间的
 36 SET @strbackup = 'C:\LogChainTest_diff_'
 37     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
 38                       ''), ':', '') + '.bak'
 39 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL;
 40 GO
 41 
 42 
 43 
 44 --第一个日志备份
 45 USE LogChainTest
 46 GO
 47 INSERT INTO tt
 48 SELECT 2
 49 DECLARE @strbackup NVARCHAR(100)
 50 --改为日期加时间的
 51 SET @strbackup = 'C:\LogChainTest_log1_'
 52     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
 53                       ''), ':', '') + '.bak'
 54 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,NO_TRUNCATE;
 55 GO
 56 
 57 USE [LogChainTest]
 58 GO
 59 SELECT *  FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC
 60 
 61 
 62 
 63 --第二个完整备份
 64 USE LogChainTest
 65 GO
 66 INSERT INTO tt
 67 SELECT 3 UNION ALL
 68 SELECT 4
 69 DECLARE @strbackup NVARCHAR(100)
 70 --改为日期加时间的
 71 SET @strbackup = 'C:\LogChainTest_full2_'
 72     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
 73                       ''), ':', '') + '.bak'
 74 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT;
 75 GO
 76 
 77 
 78 --第二个日志备份
 79 USE LogChainTest
 80 GO
 81 INSERT INTO tt
 82 SELECT 5
 83 DECLARE @strbackup NVARCHAR(100)
 84 --改为日期加时间的
 85 SET @strbackup = 'C:\LogChainTest_log2_'
 86     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
 87                       ''), ':', '') + '.bak'
 88 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,NO_TRUNCATE;
 89 GO
 90 
 91 
 92 
 93 
 94 
 95 
 96 USE master
 97 GO
 98 SELECT  *
 99 FROM    fn_dump_dblog(NULL, NULL, N'DISK', 1,
100                       N'c:\LogChainTest_full1_20131207102535.bak', DEFAULT,
101                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
102                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
103                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
104                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
105                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
106                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
107                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
108                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
109                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
110                       DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
111                       DEFAULT, DEFAULT)
View Code

我们看一下第一个日志备份和第二个日志备份之后,数据库事务日志和bak文件里面的日志数量
日备1 数据库日志

您真的理解了SQLSERVER的日志链了吗?

日备1 bak文件日志

您真的理解了SQLSERVER的日志链了吗?

日备2 数据库日志

您真的理解了SQLSERVER的日志链了吗?

日备2 bak文件日志

您真的理解了SQLSERVER的日志链了吗?

备份脚本 COPY_ONLY

您真的理解了SQLSERVER的日志链了吗?您真的理解了SQLSERVER的日志链了吗?

 1 USE master
 2 GO
 3 --创建数据库
 4 CREATE DATABASE LogChainTest;
 5 GO
 6 --改为完整恢复模式
 7 ALTER DATABASE LogChainTest SET RECOVERY FULL;
 8 GO
 9 
10 
11 
12 
13 
14 
15 --第一个完整备份
16 DECLARE @strbackup NVARCHAR(100)
17 --改为日期加时间的
18 SET @strbackup = 'C:\LogChainTest_full1_'
19     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
20                       ''), ':', '') + '.bak'
21 BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT,CHECKSUM ;
22 GO
23 
24 
25 
26 
27 
28 --第一个差异备份
29 USE LogChainTest
30 GO
31 CREATE TABLE tt(id INT)
32 INSERT INTO tt
33 SELECT 1
34 DECLARE @strbackup NVARCHAR(100)
35 --改为日期加时间的
36 SET @strbackup = 'C:\LogChainTest_diff_'
37     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
38                       ''), ':', '') + '.bak'
39 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL;
40 GO
41 
42 
43 
44 --第一个日志备份
45 USE LogChainTest
46 GO
47 INSERT INTO tt
48 SELECT 2
49 DECLARE @strbackup NVARCHAR(100)
50 --改为日期加时间的
51 SET @strbackup = 'C:\LogChainTest_log1_'
52     + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
53                       ''), ':', '') + '.bak'
54 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,COPY_ONLY;
55 GO
56 
57 USE [LogChainTest]
58您真的理解了SQLSERVER的日志链了吗?

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。