您真的理解了SQLSERVER的日志链了吗?
?您真的理解了SQLSERVER的日志鏈了嗎?
先感謝宋沄劍給本人指點(diǎn)迷津,還有郭忠輝童鞋今天在QQ群里拋出的問(wèn)題
這個(gè)問(wèn)題跟宋沄劍討論了三天,再次感謝宋沄劍
?
一直以來(lái),SQLSERVER提供了一個(gè)非常好的管理工具:SSMS
又因?yàn)檫@個(gè)管理工具太好了,所有操作的簡(jiǎn)單化,以至于使我們中毒太深,
對(duì)于SQLSERVER內(nèi)部的一些概念搞得不清不楚
比如這些概念:日志備份鏈,備份日志鏈,日志鏈,備份鏈,備份集
?
大部分都是由于SSMS的界面所導(dǎo)致,有時(shí)候有些問(wèn)題做一下實(shí)驗(yàn)就可以驗(yàn)證了,偏偏我們信賴了GUI
?
閱讀下文之前大家可以先看一下宋沄劍的文章
SQL Server CheckPoint的幾個(gè)誤區(qū)
再談SQL Server中日志的的作用
SQL Server誤區(qū)30日談-Day20-破壞日志備份鏈之后,需要一個(gè)完整備份來(lái)重新開(kāi)始日志鏈
?
先說(shuō)清楚這些概念吧
SQLSERVER只有日志鏈,備份記錄(有些人也叫備份鏈)本人覺(jué)得叫備份記錄更合適
下面三個(gè)東西說(shuō)的都是同一樣?xùn)|西
備份集=備份記錄=備份鏈
備份集:比如備份的集合,比如有對(duì)一個(gè)數(shù)據(jù)庫(kù)的完備1、差備、日備1、完備2、日備2,這些數(shù)據(jù)庫(kù)的備份的集合就是備份集
不過(guò)我更喜歡叫備份記錄
備份記錄實(shí)際上指 SELECT * FROM [msdb].[dbo].[backupset]
截?cái)嗳罩靖罩炬湐嗔咽欠袷峭粯訓(xùn)|西?
截?cái)嗳罩靖罩炬湐嗔巡皇峭粯訓(xùn)|西
什么是日志鏈
其實(shí)大家可以把bak文件理解成一個(gè)壓縮包,完整備份和差異備份的時(shí)候會(huì)把數(shù)據(jù)和日志一起帶進(jìn)壓縮包,
而日志備份的時(shí)候只會(huì)把日志帶進(jìn)壓縮包
我們先從一個(gè)實(shí)驗(yàn)開(kāi)始吧
測(cè)試環(huán)境:SQLSERVER2012 開(kāi)發(fā)版
腳本
為了不產(chǎn)生額外的日志,所以腳本里面沒(méi)有select into語(yǔ)句,本來(lái)想select into進(jìn)去臨時(shí)表再對(duì)臨時(shí)表進(jìn)行排序
但是因?yàn)閟elect into會(huì)產(chǎn)生額外的日志,只有直接對(duì)fn_dblog進(jìn)行排序了
創(chuàng)建數(shù)據(jù)庫(kù)
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO View Code查看當(dāng)前的事務(wù)日志
1 USE [LogChainTest] 2 GO 3 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC View Code進(jìn)行完整備份
1 --第一個(gè)完整備份 2 DECLARE @strbackup NVARCHAR(100) 3 --改為日期加時(shí)間的 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文件中的事務(wù)日志
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我們?cè)俨榭创藭r(shí)的數(shù)據(jù)庫(kù)事務(wù)日志
1 USE [LogChainTest] 2 GO 3 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC View Code發(fā)現(xiàn)完整備份之后事務(wù)日志比之前少了69-10=59行
我們發(fā)現(xiàn)bak文件中只記錄AllocUnitId,而不記錄表名,可能因?yàn)閎ak文件里的日志給SQLSERVER還原用的
而不是給用戶查看事務(wù)日志用的,所以SQLSERVER干脆不記錄表名了,以節(jié)省備份時(shí)間
看到這里大家會(huì)有問(wèn)題了,為什麼日志會(huì)截?cái)嗔?#xff1f;完整備份之后事務(wù)日志比之前少了69-10=59行
這里只能說(shuō)明SQLSERVER把一些跟本數(shù)據(jù)庫(kù)無(wú)關(guān)緊要的日志截?cái)嗔?#xff0c;例如創(chuàng)建數(shù)據(jù)庫(kù)時(shí)候修改master數(shù)據(jù)庫(kù)的表
而不能說(shuō)完整備份可以截?cái)嗳罩?/p>
而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/
問(wèn)題:為什麼bak文件里的日志的最后的三條記錄會(huì)是
LOP_BEGIN_CKPT
LOP_XACT_CKPT
LOP_END_CKPT
我們用下圖來(lái)表示吧
?
這里大家可以看一下宋沄劍的文章:再談SQL Server中日志的的作用
?將CheckPoint標(biāo)記寫入日志(標(biāo)記中包含當(dāng)前數(shù)據(jù)庫(kù)中活動(dòng)的事務(wù)信息),并將Log Block寫入持久化存儲(chǔ)
我在開(kāi)頭說(shuō)過(guò)事務(wù)日志中會(huì)放進(jìn)去bak文件里,但是并不是整個(gè)事務(wù)日志文件里的日志記錄全部放進(jìn)去
而是把(1)已經(jīng)checkpoint了的 (2)LAZY WRITTER?? (3)EAGER WRITTER
還是看宋沄劍的文章吧,這麼復(fù)雜的過(guò)程我就不概括了:再談SQL Server中日志的的作用
還有paul的文章:
Debunking a couple of myths around full database backups(揭穿一系列數(shù)據(jù)庫(kù)完備的誤區(qū))
More on how much transaction log a full backup includes(數(shù)據(jù)庫(kù)完備包含了多少事務(wù)日志)
實(shí)際上checkpoint和數(shù)據(jù)庫(kù)備份有著密切聯(lián)系,備份的時(shí)候SQLSERVER需要將哪些數(shù)據(jù)存入去bak文件
而在備份期間所新生成的事務(wù)和變化的數(shù)據(jù)要不要存入bak文件,這里面比較復(fù)雜,就不詳細(xì)說(shuō)了
不過(guò)有一點(diǎn)要說(shuō)的是:在數(shù)據(jù)庫(kù)備份之前,數(shù)據(jù)庫(kù)引擎會(huì)自動(dòng)執(zhí)行checkpoint,以便在備份中包含對(duì)數(shù)據(jù)庫(kù)頁(yè)的全部更改。
我摘抄了網(wǎng)上的一些資料
1 http://blog.csdn.net/tjvictor/article/details/5209604 2 導(dǎo)致CheckPoint檢查點(diǎn)的事件: 1.在數(shù)據(jù)庫(kù)備份之前,數(shù)據(jù)庫(kù)引擎會(huì)自動(dòng)執(zhí)行checkpoint,以便在備份中包含對(duì)數(shù)據(jù)庫(kù)頁(yè)的全部更改。 3 4 2.日志的活動(dòng)部分超出了服務(wù)器在 recovery interval 服務(wù)器配置選項(xiàng)中指定的時(shí)間內(nèi)可以恢復(fù)的大小。 5 6 3.日志的 70% 已滿,并且數(shù)據(jù)庫(kù)處于日志截?cái)嗄J健? 7 8 當(dāng)下列條件都為 TRUE 時(shí),數(shù)據(jù)庫(kù)就處于日志截?cái)嗄J?#xff1a;數(shù)據(jù)庫(kù)使用的是簡(jiǎn)單恢復(fù)模式,并且在執(zhí)行上一條引用數(shù)據(jù)庫(kù)的 BACKUP DATABASE 語(yǔ)句后,發(fā)生下列事件之一: 9 10 在數(shù)據(jù)庫(kù)中執(zhí)行一項(xiàng)最小日志記錄大容量復(fù)制操作或一條最條小日志記錄的 WRITETEXT 語(yǔ)句。 11 12 執(zhí)行一個(gè)在數(shù)據(jù)庫(kù)中添加或刪除文件的 ALTER DATABASE 語(yǔ)句。 13 14 4.停止服務(wù)器也會(huì)在服務(wù)器上的每個(gè)數(shù)據(jù)庫(kù)中發(fā)出一個(gè)檢查點(diǎn)命令。下列停止 SQL Server 的方法將為每個(gè)數(shù)據(jù)庫(kù)執(zhí)行檢查點(diǎn): 15 16 使用 SQL Server 配置管理器。 17 18 使用 SQL Server Management Studio。 19 20 使用 SHUTDOWN 語(yǔ)句。 21 -------------------------------------------------------------------------- 22 http://www.cnblogs.com/CareySon/p/3315041.html 23 5.將恢復(fù)間隔設(shè)置為1分鐘,意味著每1分鐘會(huì)對(duì)所有的數(shù)據(jù)庫(kù)做一次CheckPoint 24 25 錯(cuò)誤。將恢復(fù)間隔設(shè)置為1分鐘不能想成建立一個(gè)Agent,每分鐘寫一個(gè)CheckPoint命令,這是兩碼事。這只是意味著每分鐘去檢查一次是否需要做CheckPoint,如果期間積累的日志量足夠,才會(huì)對(duì)積累足夠日志量的數(shù)據(jù)庫(kù)去做CheckPoint。即使中間積累了巨量的日志,不到1分鐘也不會(huì)做CheckPoint。 View Code?
?
那么大家可以將bak文件里的事務(wù)日志當(dāng)作為數(shù)據(jù)庫(kù)事務(wù)日志
?
備份腳本
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 13 14 15 --第一個(gè)完整備份 16 DECLARE @strbackup NVARCHAR(100) 17 --改為日期加時(shí)間的 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 --第一個(gè)差異備份 29 USE LogChainTest 30 GO 31 CREATE TABLE tt(id INT) 32 INSERT INTO tt 33 SELECT 1 34 DECLARE @strbackup NVARCHAR(100) 35 --改為日期加時(shí)間的 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 --第一個(gè)日志備份 45 USE LogChainTest 46 GO 47 INSERT INTO tt 48 SELECT 2 49 DECLARE @strbackup NVARCHAR(100) 50 --改為日期加時(shí)間的 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 --第二個(gè)完整備份 61 USE master 62 GO 63 DECLARE @strbackup NVARCHAR(100) 64 --改為日期加時(shí)間的 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 --第二個(gè)日志備份 73 USE LogChainTest 74 GO 75 INSERT INTO tt 76 SELECT 3 77 DECLARE @strbackup NVARCHAR(100) 78 --改為日期加時(shí)間的 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
還原腳本
1 --差異備份和日志備份1打亂 2 USE master 3 GO 4 --還原第一個(gè)完整備份 5 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131206230857.bak' 6 WITH REPLACE ,CHECKSUM, NORECOVERY 7 GO 8 9 --還原第一個(gè)日志備份 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,級(jí)別 16,狀態(tài) 3,第 1 行 20 無(wú)法還原此差異備份,因?yàn)樵摂?shù)據(jù)庫(kù)尚未還原到正確的早期狀態(tài)。 21 消息 3013,級(jí)別 16,狀態(tài) 1,第 1 行 22 RESTORE DATABASE 正在異常終止。 23 24 25 26 27 --還原第二個(gè)日志備份,沒(méi)有報(bào)錯(cuò) 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,再還原差異備份結(jié)果就報(bào)錯(cuò)了
1 消息 3136,級(jí)別 16,狀態(tài) 3,第 1 行 2 無(wú)法還原此差異備份,因?yàn)樵摂?shù)據(jù)庫(kù)尚未還原到正確的早期狀態(tài)。 3 消息 3013,級(jí)別 16,狀態(tài) 1,第 1 行 4 RESTORE DATABASE 正在異常終止。還有,為什麼不用還原完整備份2數(shù)據(jù)也沒(méi)有丟失??
?
我們每次備份的時(shí)候,無(wú)論是完備、差備、日備都會(huì)把日志拷貝到bak文件里
而拷貝的時(shí)候會(huì)有一個(gè)last lsn確保日志順序
當(dāng)我先還原日志備份1,然后還原差異備份的時(shí)候因?yàn)閘ast lsn的順序不對(duì)所以就報(bào)錯(cuò)了
?
為什麼不用還原完整備份2數(shù)據(jù)也沒(méi)有丟失??
這里先說(shuō)一下完備、差備、日備的大概方式
完備:復(fù)制數(shù)據(jù)和少量的log到bak
差備:復(fù)制有差異的數(shù)據(jù)和少量的log到bak
日備:不復(fù)制數(shù)據(jù),如果是第一次日備,會(huì)把所有的log復(fù)制到bak,如果是第二次日備,會(huì)把自上一次日備到這次日備的log復(fù)制到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
我們沒(méi)有還原完整備份2(相當(dāng)于丟失了完整備份2),我們的還原順序是
還原完整備份1(復(fù)制數(shù)據(jù),根據(jù)redo/undo log保證事務(wù)一致性)
還原差異備份(復(fù)制差異數(shù)據(jù),根據(jù)redo/undo log保證事務(wù)一致性)
還原日志備份1(數(shù)據(jù)全靠redo/undo log來(lái)恢復(fù),根據(jù)redo/undo log保證事務(wù)一致性)
還原日志備份2(數(shù)據(jù)全靠redo/undo log來(lái)恢復(fù),根據(jù)redo/undo log保證事務(wù)一致性)
因?yàn)槿罩緜浞?里面已經(jīng)包含了從日志備份1到日志備份2的所有l(wèi)og,所以SQLSERVER可以憑借這些log來(lái)把數(shù)據(jù)恢復(fù)
而日志備份1里面已經(jīng)包含了從完整備份1到日志備份1的所有l(wèi)og
所以,按理說(shuō),我們只需要還原完備1,日備1,日備2就可以恢復(fù)全部數(shù)據(jù)
?
測(cè)試:
我們使用下面?zhèn)浞菽_本和還原腳本,看一下不還原日志備份1,直接還原日志備份2看有沒(méi)有問(wèn)題
備份腳本
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 13 14 15 --第一個(gè)完整備份 16 DECLARE @strbackup NVARCHAR(100) 17 --改為日期加時(shí)間的 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 --第一個(gè)差異備份 29 USE LogChainTest 30 GO 31 CREATE TABLE tt(id INT) 32 INSERT INTO tt 33 SELECT 1 34 DECLARE @strbackup NVARCHAR(100) 35 --改為日期加時(shí)間的 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 --第一個(gè)日志備份 45 USE LogChainTest 46 GO 47 INSERT INTO tt 48 SELECT 2 49 DECLARE @strbackup NVARCHAR(100) 50 --改為日期加時(shí)間的 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 --第二個(gè)完整備份 61 USE LogChainTest 62 GO 63 INSERT INTO tt 64 SELECT 3 UNION ALL 65 SELECT 4 66 DECLARE @strbackup NVARCHAR(100) 67 --改為日期加時(shí)間的 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 --第二個(gè)日志備份 76 USE LogChainTest 77 GO 78 INSERT INTO tt 79 SELECT 5 80 DECLARE @strbackup NVARCHAR(100) 81 --改為日期加時(shí)間的 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還原腳本
1 USE master 2 GO 3 --還原第一個(gè)完整備份 4 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131207102535.bak' 5 WITH REPLACE ,NORECOVERY 6 GO 7 8 9 --還原第二個(gè)日志備份 10 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log2_20131207102602.bak' 11 WITH RECOVERY 12 GO View Code插入的數(shù)據(jù)太少,日志太少,搞得文件的size不那么明顯
結(jié)果報(bào)錯(cuò)
1 消息 4305,級(jí)別 16,狀態(tài) 1,第 2 行 2 此備份集中的日志開(kāi)始于 LSN 35000000017200001,該 LSN 太晚,無(wú)法應(yīng)用到數(shù)據(jù)庫(kù)。可以還原包含 LSN 35000000008600001 的較早的日志備份。 3 消息 3013,級(jí)別 16,狀態(tài) 1,第 2 行 4 RESTORE LOG 正在異常終止。因?yàn)闆](méi)有還原日志備份1,缺少了完備1到日備1之間的日志,所以就報(bào)錯(cuò)了
我們使用下面的腳本來(lái)進(jìn)行還原,只還原完備1,日備1,日備2
1 USE master 2 GO 3 --還原第一個(gè)完整備份 4 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131207102535.bak' 5 WITH REPLACE ,NORECOVERY 6 GO 7 8 --還原第一個(gè)日志備份 9 RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log1_20131207102542.bak' 10 WITH NORECOVERY 11 GO 12 13 --還原第二個(gè)日志備份 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這次成功了,數(shù)據(jù)都沒(méi)有丟失,那么說(shuō)明我丟失了差異備份、完整備份2也沒(méi)有關(guān)系
如果我丟失了日備1、差備、完備2,只有完備1和日備2,那么這個(gè)時(shí)候你只能祈禱了,你只能還原完備1
差備、日備1、完備2、日備2的數(shù)據(jù)都已經(jīng)丟失
BAK文件中日志數(shù)量的多少
我剛才說(shuō)
完備:復(fù)制數(shù)據(jù)和少量的log到bak
差備:復(fù)制有差異的數(shù)據(jù)和少量的log到bak
日備:不復(fù)制數(shù)據(jù),如果是第一次日備,會(huì)把所有的log復(fù)制到bak,如果是第二次日備,會(huì)把自上一次日備到這次日備的log復(fù)制到bak
我怎麼看出來(lái)的?
測(cè)試:
我們看一下每次備份完畢后,bak文件里面的日志數(shù)量
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
差備
日備1
完備2
日備2
在完備2的時(shí)候bak中的日志只有44行,說(shuō)明完整備份只存儲(chǔ)一些必要的日志,不是所有日志都存儲(chǔ)
完備存儲(chǔ)這些日志的作用是在還原的時(shí)候根據(jù)這些log去redo/undo 保證事務(wù)一致性,所以只會(huì)寫入少量日志
因?yàn)橥陚浜筒顐涠际菑?fù)制數(shù)據(jù),所以就沒(méi)有必要像日備那樣全部事務(wù)日志都復(fù)制到bak里面
而日備2為什麼只有73行記錄,因?yàn)樵谌諅?的時(shí)候SQLSERVER已經(jīng)截?cái)嗔耸聞?wù)日志,日備2的日志就像我前面說(shuō)的
如果是第二次日備,會(huì)把自上一次日備到這次日備的log復(fù)制到bak
?
如果我們不想在backup log 的時(shí)候截?cái)嗍聞?wù)日志,可以使用NO_TRUNCATE和COPY_ONLY這兩個(gè)backup option
備份腳本 NO_TRUNCATE
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 13 14 15 --第一個(gè)完整備份 16 DECLARE @strbackup NVARCHAR(100) 17 --改為日期加時(shí)間的 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 --第一個(gè)差異備份 29 USE LogChainTest 30 GO 31 CREATE TABLE tt(id INT) 32 INSERT INTO tt 33 SELECT 1 34 DECLARE @strbackup NVARCHAR(100) 35 --改為日期加時(shí)間的 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 --第一個(gè)日志備份 45 USE LogChainTest 46 GO 47 INSERT INTO tt 48 SELECT 2 49 DECLARE @strbackup NVARCHAR(100) 50 --改為日期加時(shí)間的 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 --第二個(gè)完整備份 64 USE LogChainTest 65 GO 66 INSERT INTO tt 67 SELECT 3 UNION ALL 68 SELECT 4 69 DECLARE @strbackup NVARCHAR(100) 70 --改為日期加時(shí)間的 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 --第二個(gè)日志備份 79 USE LogChainTest 80 GO 81 INSERT INTO tt 82 SELECT 5 83 DECLARE @strbackup NVARCHAR(100) 84 --改為日期加時(shí)間的 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我們看一下第一個(gè)日志備份和第二個(gè)日志備份之后,數(shù)據(jù)庫(kù)事務(wù)日志和bak文件里面的日志數(shù)量
日備1 數(shù)據(jù)庫(kù)日志
日備1 bak文件日志
日備2 數(shù)據(jù)庫(kù)日志
日備2 bak文件日志
?
備份腳本 COPY_ONLY
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 13 14 15 --第一個(gè)完整備份 16 DECLARE @strbackup NVARCHAR(100) 17 --改為日期加時(shí)間的 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 --第一個(gè)差異備份 29 USE LogChainTest 30 GO 31 CREATE TABLE tt(id INT) 32 INSERT INTO tt 33 SELECT 1 34 DECLARE @strbackup NVARCHAR(100) 35 --改為日期加時(shí)間的 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 --第一個(gè)日志備份 45 USE LogChainTest 46 GO 47 INSERT INTO tt 48 SELECT 2 49 DECLARE @strbackup NVARCHAR(100) 50 --改為日期加時(shí)間的 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 GO 59 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC 60 61 62 63 --第二個(gè)完整備份 64 USE LogChainTest 65 GO 66 INSERT INTO tt 67 SELECT 3 UNION ALL 68 SELECT 4 69 DECLARE @strbackup NVARCHAR(100) 70 --改為日期加時(shí)間的 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 --第二個(gè)日志備份 79 USE LogChainTest 80 GO 81 INSERT INTO tt 82 SELECT 5 83 DECLARE @strbackup NVARCHAR(100) 84 --改為日期加時(shí)間的 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,COPY_ONLY; 89 GO 90 91 USE [LogChainTest] 92 GO 93 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC View Code我們看一下第一個(gè)日志備份和第二個(gè)日志備份之后,數(shù)據(jù)庫(kù)事務(wù)日志和bak文件里面的日志數(shù)量
日備1 數(shù)據(jù)庫(kù)日志
日備1 bak文件日志
日備2 數(shù)據(jù)庫(kù)日志
日備2 bak文件日志
?
大家可以看一下這篇帖子
完整備份能截?cái)嗳罩締?#xff1f;
差異備份的作用
既然SQLSERVER靠bak文件里的日志來(lái)進(jìn)行redo/undo,就像上面說(shuō)的那樣,靠完備1,日備1,日備2就可以恢復(fù)所有數(shù)據(jù)
那么差異備份有什么用呢??
為什麼要有差異備份呢?
差異備份是為了RTO(Recovery Time Objective)
詳見(jiàn):http://blog.sina.com.cn/s/blog_59388e440100oq52.html
如果只做日志備份RTO有可能保證不了
之前說(shuō)過(guò):差備:復(fù)制有差異的數(shù)據(jù)和少量的log到bak
差異備份:靠DCM頁(yè)面復(fù)制粘貼把bak文件里的數(shù)據(jù)復(fù)制粘貼到mdf文件的數(shù)據(jù)頁(yè)
日志備份:redo/undo log
這兩個(gè)選項(xiàng)肯定是復(fù)制粘貼在速度上占優(yōu)勢(shì)
當(dāng)還原了差異備份之后,SQLSERVER根據(jù)差異備份時(shí)候的log使數(shù)據(jù)庫(kù)保存了事務(wù)一致性,然后還原日備1
還原日備1的時(shí)候,SQLSERVER根據(jù)差備的last lsn,只需要redo/undo 差備-》日備1這段時(shí)間的log就可以了
這樣節(jié)省了時(shí)間,不用redo/undo 完備1-》日備1這段時(shí)間的log,從而保證了RTO
而日志備份,本人覺(jué)得是為了保證RPO(Recovery Point Objective)
被神化的日志鏈
實(shí)際上日志鏈就是我上面說(shuō)的數(shù)據(jù)庫(kù)事務(wù)日志,只是備份的時(shí)候,SQLSERVER把事務(wù)日志放進(jìn)去bak文件里
我畫了幾張圖
上面那個(gè)實(shí)驗(yàn)的理解圖
-------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
大家可以使用下面兩個(gè)SQL語(yǔ)句
1 SELECT * FROM [sys].[fn_dblog]() 2 SELECT * FROM [sys].[fn_dump_dblog]()在完整備份、差異備份、日志備份測(cè)試一下在哪種備份類型下日志會(huì)被截?cái)?#xff0c;截?cái)嗟囊馑?#xff08;數(shù)據(jù)庫(kù)事務(wù)日志的記錄數(shù)比bak文件里的日志記錄數(shù)少)
就像我在開(kāi)頭做的那個(gè)實(shí)驗(yàn)一樣
?
GUI界面下,默認(rèn)就是截?cái)嗍聞?wù)日志,很多人都以為截?cái)嗍聞?wù)日志要加X(jué)X backup option才可以截?cái)?/p>
?
如何查看last_log_backup_lsn這個(gè)值
select last_log_backup_lsn from sys.database_recovery_status WHERE [database_id]=DB_ID('test')last_log_backup_lsn這個(gè)值在boot page的last_log_backup_lsn項(xiàng)里保存,表示對(duì)數(shù)據(jù)庫(kù)執(zhí)行最后一次事務(wù)日志備份中的最大LSN號(hào),也可以說(shuō)是下一次事務(wù)日志備份的開(kāi)始LSN
?
實(shí)驗(yàn)
USE [test] select last_log_backup_lsn from sys.database_recovery_status WHERE [database_id]=DB_ID('test')BACKUP DATABASE [test] TO DISK ='D:\DBBackup\testfull.bak' USE [test] select last_log_backup_lsn from sys.database_recovery_status WHERE [database_id]=DB_ID('test') --34000000031500001BACKUP LOG [test] TO DISK ='D:\DBBackup\testlog1.bak' USE [test] select last_log_backup_lsn from sys.database_recovery_status WHERE [database_id]=DB_ID('test') --34000000032300001BACKUP LOG [test] TO DISK ='D:\DBBackup\testlog2.bak' USE [test] select last_log_backup_lsn from sys.database_recovery_status WHERE [database_id]=DB_ID('test')--34000000032800001USE [master] RESTORE DATABASE [test] FROM DISK = N'D:\DBBackup\testfull.bak' WITH FILE = 1, MOVE N'test' TO N'D:\MSSQL\test.mdf', MOVE N'test_log' TO N'D:\MSSQL\test_log.ldf', NOUNLOAD,NORECOVERY , STATS = 5GOUSE [master] RESTORE DATABASE [test] FROM DISK = N'D:\DBBackup\testlog2.bak' WITH FILE = 1, NOUNLOAD,NORECOVERY , STATS = 5GO 消息 4305,級(jí)別 16,狀態(tài) 1,第 2 行 此備份集中的日志開(kāi)始于 LSN 34000000032300001,該 LSN 太晚,無(wú)法應(yīng)用到數(shù)據(jù)庫(kù)。可以還原包含 LSN 34000000031500001 的較早的日志備份。 消息 3013,級(jí)別 16,狀態(tài) 1,第 2 行 RESTORE DATABASE 正在異常終止。可以看到,還原日志備份的時(shí)候是讀取boot page的?last_log_backup_lsn的值來(lái)判斷日志序列,此處應(yīng)該先還原LSN 34000000032300001的日志備份
日志鏈斷裂的情況
paul的文章說(shuō)了 SQL Server誤區(qū)30日談-Day20-破壞日志備份鏈之后,需要一個(gè)完整備份來(lái)重新開(kāi)始日志鏈
下面這幾種操作都有可能引起日志鏈斷裂
(1)由完整恢復(fù)模式或大容量事務(wù)日志恢復(fù)模式轉(zhuǎn)為簡(jiǎn)單恢復(fù)模式
(2)從數(shù)據(jù)庫(kù)鏡像進(jìn)行恢復(fù)
(3)備份日志時(shí)指定了NO_LOG 或 WITH TRUNCATE_ONLY(還好在SQL Server 2008中這個(gè)選項(xiàng)被取消了)
本人覺(jué)得日志鏈斷裂是一個(gè)非常專業(yè)的名稱
很多人以為,我做了下面的備份策略:完備1-》差備-》日備1-》完備2-》日備2
如果差備丟失了就認(rèn)為是日志鏈斷裂了,數(shù)據(jù)庫(kù)不能還原到日備1
?
其實(shí)日志鏈斷裂通俗的理解就是:沒(méi)有將日志放進(jìn)去bak文件里
怎樣的情況才叫? 沒(méi)有將日志放進(jìn)去bak文件里呢??
我們知道當(dāng)我們進(jìn)行完備、差備、日備的時(shí)候都會(huì)把日志放進(jìn)去bak文件里
情況一:
當(dāng)你將數(shù)據(jù)庫(kù)恢復(fù)模式由完整恢復(fù)模式或大容量事務(wù)日志恢復(fù)模式轉(zhuǎn)為簡(jiǎn)單恢復(fù)模式
大家還是先看一下這篇文章吧:SQL Server日志在簡(jiǎn)單恢復(fù)模式下的角色
簡(jiǎn)單恢復(fù)模式的機(jī)制是:文章中有這樣一句話
“在簡(jiǎn)單恢復(fù)模式下,每一次CheckPoint,都會(huì)去檢查是否有日志可以截?cái)?#xff0c;如果有inactive的VLF時(shí),
CheckPoint都會(huì)將可截?cái)嗖糠诌M(jìn)行截?cái)?#xff0c;并將MinLSN向后推”
簡(jiǎn)單來(lái)講就是簡(jiǎn)單恢復(fù)模式不是在backup log?DB 的情況下截?cái)嗳罩?/p>
?
而是在checkpoint的時(shí)候截?cái)嗳罩?#xff0c;那么既然在checkpoint的時(shí)候已經(jīng)截?cái)嗔巳罩?#xff0c;在備份的時(shí)候數(shù)據(jù)庫(kù)的事務(wù)日志
就沒(méi)有不活動(dòng)日志用于歸檔(把日志放進(jìn)去bak文件)
?
?
?
我們使用下面的腳本進(jìn)行日志備份就會(huì)報(bào)錯(cuò)
1 USE master 2 GO 3 CREATE DATABASE LogChainTest; 4 GO 5 ALTER DATABASE LogChainTest SET RECOVERY SIMPLE; 6 GO 7 8 DECLARE @strbackup NVARCHAR(100) 9 --改為日期加時(shí)間的 10 SET @strbackup = 'C:\LogChainTest_log_' 11 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 12 ''), ':', '') + '.bak' 13 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT; 14 GO View Code 1 消息 4208,級(jí)別 16,狀態(tài) 1,第 6 行 2 當(dāng)恢復(fù)模式為 SIMPLE 時(shí),不允許使用 BACKUP LOG 語(yǔ)句。請(qǐng)使用 BACKUP DATABASE 或用 ALTER DATABASE 更改恢復(fù)模式。 3 消息 3013,級(jí)別 16,狀態(tài) 1,第 6 行 4 BACKUP LOG 正在異常終止。但是完整備份和差異備份則不受影響
備份腳本
1 USE master 2 GO 3 CREATE DATABASE LogChainTest; 4 GO 5 ALTER DATABASE LogChainTest SET RECOVERY SIMPLE; 6 GO 7 8 --第一個(gè)完整備份 9 DECLARE @strbackup NVARCHAR(100) 10 --改為日期加時(shí)間的 11 SET @strbackup = 'C:\LogChainTest_full1_' 12 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 13 ''), ':', '') + '.bak' 14 BACKUP DATABASE LogChainTest TO DISK =@strbackup WITH INIT,CHECKSUM ; 15 GO 16 17 18 19 --第一個(gè)差異備份 20 USE LogChainTest 21 GO 22 CREATE TABLE tt(id int) 23 INSERT INTO tt 24 SELECT 1 25 DECLARE @strbackup NVARCHAR(100) 26 --改為日期加時(shí)間的 27 SET @strbackup = 'C:\LogChainTest_diff1_' 28 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 29 ''), ':', '') + '.bak' 30 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL; 31 GO 32 33 --第二個(gè)差異備份 34 USE LogChainTest 35 GO 36 INSERT INTO tt 37 SELECT 9 38 DECLARE @strbackup NVARCHAR(100) 39 --改為日期加時(shí)間的 40 SET @strbackup = 'C:\LogChainTest_diff2_' 41 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 42 ''), ':', '') + '.bak' 43 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL; 44 GO View Code完整備份和差異備份可以用下圖來(lái)理解,少量活動(dòng)日志放到bak文件里用于保證事務(wù)一致性
完整備份差異備份時(shí)依然會(huì)將last lsn寫入bak文件里
還原腳本
1 --還原第一個(gè)完整備份 2 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131207120946.bak' 3 WITH REPLACE , NORECOVERY 4 GO 5 6 --還原第二個(gè)差異備份 7 RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_diff2_20131207121428.bak' 8 WITH NORECOVERY 9 GO 10 11 --還原第一個(gè)差異備份 12 RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_diff_20131207120957.bak' 13 WITH RECOVERY 14 GO View Code先還原差備2再還原差備1就報(bào)錯(cuò)
1 消息 4305,級(jí)別 16,狀態(tài) 1,第 1 行 2 此備份集中的日志開(kāi)始于 LSN 35000000028200004,該 LSN 太晚,無(wú)法應(yīng)用到數(shù)據(jù)庫(kù)。可以還原包含 LSN 35000000024100001 的較早的日志備份。 3 消息 3013,級(jí)別 16,狀態(tài) 1,第 1 行 4 RESTORE LOG 正在異常終止。實(shí)際上完整和差備都是復(fù)制數(shù)據(jù)和少量活動(dòng)日志到bak里面,所以還原是沒(méi)有問(wèn)題的
但是日備不同,日備需要將完備到第一個(gè)日備的log,或者自上一次日備到這次日備的log全部放進(jìn)去bak文件
因?yàn)楹?jiǎn)單恢復(fù)模式是一checkpoint就截?cái)嗳罩?#xff0c;根本無(wú)辦法保存完整的log,所以是不允許日備的
?
情況二:
備份日志時(shí)指定了NO_LOG 或 WITH TRUNCATE_ONLY(還好在SQL Server 2008中這個(gè)選項(xiàng)被取消了)
TRUNCATE_ONLY的意思是只截?cái)嗳罩静粋浞萑罩镜絙ak文件里(只能用在backup log語(yǔ)句)
NO_LOG的意思是不備份日志到bak文件里(不備份日志到bak文件里意味著不能backup log,當(dāng)然也意味著不能截?cái)嗳罩?#xff09;
我們轉(zhuǎn)到SQLSERVER2005
備份腳本
NO_LOG
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 --第一個(gè)完整備份 11 DECLARE @strbackup NVARCHAR(100) 12 --改為日期加時(shí)間的 13 SET @strbackup = 'C:\LogChainTest_full1_' 14 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 15 ''), ':', '') + '.bak' 16 BACKUP DATABASE LogChainTest TO DISK =@strbackup WITH INIT,NO_LOG ; 17 GO 18 19 已為數(shù)據(jù)庫(kù) 'LogChainTest',文件 'LogChainTest' (位于文件 1 上)處理了 176 頁(yè)。 20 BACKUP DATABASE...FILE=<name> 成功處理了 176 頁(yè),花費(fèi) 0.025 秒(57.671 MB/秒)。 21 22 23 24 --第一個(gè)差異備份 25 USE LogChainTest 26 GO 27 CREATE TABLE tt(id INT) 28 INSERT INTO tt 29 SELECT 1 30 DECLARE @strbackup NVARCHAR(100) 31 --改為日期加時(shí)間的 32 SET @strbackup = 'C:\LogChainTest_diff_' 33 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 34 ''), ':', '') + '.bak' 35 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL,NO_LOG; 36 GO 37 38 39 (1 行受影響) 40 已為數(shù)據(jù)庫(kù) 'LogChainTest',文件 'LogChainTest' (位于文件 1 上)處理了 96 頁(yè)。 41 BACKUP DATABASE...FILE=<name> WITH DIFFERENTIAL 成功處理了 96 頁(yè),花費(fèi) 0.016 秒(49.152 MB/秒)。 42 43 44 45 --第一個(gè)日志備份 46 USE LogChainTest 47 GO 48 INSERT INTO tt 49 SELECT 2 50 DECLARE @strbackup NVARCHAR(100) 51 --改為日期加時(shí)間的 52 SET @strbackup = 'C:\LogChainTest_log1_' 53 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 54 ''), ':', '') + '.bak' 55 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,NO_LOG; 56 GO View Code備份策略:完備-》差備-》日備
大家可以看到執(zhí)行日備的時(shí)候沒(méi)有產(chǎn)生bak文件
查看bak文件里的日志
1 SELECT * 2 FROM fn_dump_dblog(NULL, NULL, N'DISK', 1, 3 N'c:\LogChainTest_full1_20131207123314.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完備0行
差備0行
其實(shí)可以用下圖來(lái)理解
bak文件里只有數(shù)據(jù)沒(méi)有日志,連保證事務(wù)一致性的少量的活動(dòng)日志都沒(méi)有
?
備份腳本
TRUNCATE_ONLY
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 --日備前的事務(wù)日志記錄 11 USE [LogChainTest] 12 GO 13 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC 14 15 16 --日志備份 17 USE LogChainTest 18 GO 19 CREATE TABLE tt(id INT) 20 INSERT INTO tt 21 SELECT 2 22 DECLARE @strbackup NVARCHAR(100) 23 --改為日期加時(shí)間的 24 SET @strbackup = 'C:\LogChainTest_log1_' 25 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 26 ''), ':', '') + '.bak' 27 BACKUP LOG LogChainTest TO DISK = @strbackup WITH TRUNCATE_ONLY; 28 GO 29 30 --日備后的事務(wù)日志記錄 31 USE [LogChainTest] 32 GO 33 SELECT * FROM [sys].[fn_dblog](NULL,NULL) ORDER BY [Begin Time] ASC 34 35 36 37 SELECT * 38 FROM fn_dump_dblog(NULL, NULL, N'DISK', 1, 39 N'c:\LogChainTest_diff_20131207123347.bak', DEFAULT, 40 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 41 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 42 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 43 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 44 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 45 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 46 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 47 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 48 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 49 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 50 DEFAULT, DEFAULT) View Code備份策略:日備
大家可以看到執(zhí)行日備的時(shí)候沒(méi)有產(chǎn)生bak文件
查看日志備份前數(shù)據(jù)庫(kù)事務(wù)日志
查看日志備份前數(shù)據(jù)庫(kù)事務(wù)日志
其實(shí)可以用下圖來(lái)理解
truncate_only只是截?cái)嗔巳罩?#xff0c;沒(méi)有產(chǎn)生bak文件,更不用說(shuō)備份日志到bak文件里面了
我們?cè)僮鲆粋€(gè)實(shí)驗(yàn)
備份腳本
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 --第一個(gè)完整備份 13 USE master 14 GO 15 DECLARE @strbackup NVARCHAR(100) 16 --改為日期加時(shí)間的 17 SET @strbackup = 'C:\LogChainTest_full1_' 18 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 19 ''), ':', '') + '.bak' 20 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT; 21 GO 22 23 24 25 --第一個(gè)日志備份 26 USE LogChainTest 27 GO 28 CREATE TABLE tt(id INT) 29 INSERT INTO tt 30 SELECT 1 31 DECLARE @strbackup NVARCHAR(100) 32 --改為日期加時(shí)間的 33 SET @strbackup = 'C:\LogChainTest_log1_' 34 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 35 ''), ':', '') + '.bak' 36 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT; 37 GO 38 39 40 --第二個(gè)日志備份WITH TRUNCATE_ONLY 41 USE LogChainTest 42 GO 43 INSERT INTO tt 44 SELECT 2 45 DECLARE @strbackup NVARCHAR(100) 46 --改為日期加時(shí)間的 47 SET @strbackup = 'C:\LogChainTest_log2_' 48 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 49 ''), ':', '') + '.bak' 50 BACKUP LOG LogChainTest TO DISK = @strbackup WITH TRUNCATE_ONLY; 51 GO 52 53 54 --第三個(gè)日志備份 55 USE LogChainTest 56 GO 57 INSERT INTO tt 58 SELECT 3 59 DECLARE @strbackup NVARCHAR(100) 60 --改為日期加時(shí)間的 61 SET @strbackup = 'C:\LogChainTest_log3_' 62 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 63 ''), ':', '') + '.bak' 64 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT; 65 GO View Code當(dāng)我進(jìn)行到第三個(gè)日志備份的時(shí)候就報(bào)錯(cuò)了
1 (1 行受影響) 2 消息 4214,級(jí)別 16,狀態(tài) 1,第 8 行 3 無(wú)法執(zhí)行 BACKUP LOG,因?yàn)楫?dāng)前沒(méi)有數(shù)據(jù)庫(kù)備份。 4 消息 3013,級(jí)別 16,狀態(tài) 1,第 8 行 5 BACKUP LOG 正在異常終止。可以用下圖來(lái)理解
?
(2)從數(shù)據(jù)庫(kù)鏡像進(jìn)行恢復(fù)這種情況由于沒(méi)有研究過(guò)就不說(shuō)了
小結(jié):
截?cái)嗳罩靖罩炬湐嗔巡皇峭粯訓(xùn)|西!!
截?cái)嗳罩?針對(duì)數(shù)據(jù)庫(kù)事務(wù)日志
日志鏈斷裂:針對(duì)bak里的日志
大家不要混淆了
不神秘的事務(wù)日志尾部
當(dāng)你的數(shù)據(jù)庫(kù)損壞或置疑,你可以嘗試進(jìn)行尾日志備份
尾日志指的是哪個(gè)地方? 為什麼要進(jìn)行尾日志備份?
假如有下面的腳本
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 12 --第一個(gè)完整備份 13 DECLARE @strbackup NVARCHAR(100) 14 --改為日期加時(shí)間的 15 SET @strbackup = 'C:\LogChainTest_full1_' 16 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 17 ''), ':', '') + '.bak' 18 BACKUP DATABASE LogChainTest TO DISK =@strbackup WITH INIT,CHECKSUM ; 19 GO 20 21 22 23 --第一個(gè)日志備份 24 USE LogChainTest 25 GO 26 CREATE TABLE tt(id INT) 27 INSERT INTO tt 28 SELECT 1 29 DECLARE @strbackup NVARCHAR(100) 30 --改為日期加時(shí)間的 31 SET @strbackup = 'C:\LogChainTest_log1_' 32 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 33 ''), ':', '') + '.bak' 34 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,COPY_ONLY; 35 GO 36 37 38 39 40 41 --第二個(gè)日志備份 42 USE LogChainTest 43 GO 44 INSERT INTO tt 45 SELECT 2 46 DECLARE @strbackup NVARCHAR(100) 47 --改為日期加時(shí)間的 48 SET @strbackup = 'C:\LogChainTest_log2_' 49 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 50 ''), ':', '') + '.bak' 51 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,COPY_ONLY; 52 GO 53 54 55 --在第二個(gè)日志備份后插入記錄到tt表 56 INSERT INTO tt 57 SELECT 3 View Code在第二個(gè)日志備份之后還插入了一條記錄到tt表
如果這時(shí)候數(shù)據(jù)庫(kù)損壞,那么你可以備份事務(wù)日志尾部,把最后的事務(wù)日志記錄(INSERT INTO tt
SELECT 3)放進(jìn)去bak文件里,然后進(jìn)行還原數(shù)據(jù)庫(kù)
?
使用下面腳本,備份日志尾部
注意:數(shù)據(jù)庫(kù)離線的狀態(tài)下是不能備份日志尾部的!!
網(wǎng)上很多文章都誤導(dǎo)人
由于數(shù)據(jù)庫(kù) 'LogChainTest' 離線,無(wú)法打開(kāi)該數(shù)據(jù)庫(kù)
1 --備份日志尾部 2 USE master 3 GO 4 DECLARE @strbackup NVARCHAR(100) 5 --改為日期加時(shí)間的 6 SET @strbackup = 'C:\LogChainTest_log_tail_' 7 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 8 ''), ':', '') + '.bak' 9 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT,NORECOVERY; 10 GO View Code這時(shí)候數(shù)據(jù)庫(kù)顯示正在還原
還原腳本
數(shù)據(jù)沒(méi)有丟失,可以查出最后一條插入到tt表的記錄3
?
回答開(kāi)頭的問(wèn)題:尾日志指的是哪個(gè)地方? 為什麼要進(jìn)行尾日志備份?
其實(shí)備份日志尾部,大家可以把他作為普通的事務(wù)日志備份
如果遇到錯(cuò)誤還可以加上CONTINUE_AFTER_ERROR 的backup option
1 --備份日志尾部 2 USE master 3 GO 4 DECLARE @strbackup NVARCHAR(100) 5 --改為日期加時(shí)間的 6 SET @strbackup = 'C:\LogChainTest_log_tail_' 7 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 8 ''), ':', '') + '.bak' 9 BACKUP LOG LogChainTest TO DISK = @strbackup WITH CONTINUE_AFTER_ERROR,NORECOVERY; 10 GO View Code?
備份記錄
實(shí)際上這個(gè)[msdb].[dbo].[backupset]表的作用只是給你看做了哪些備份
1 SELECT * FROM [msdb].[dbo].[backupset]?
使用GUI的時(shí)候,我發(fā)現(xiàn)了一個(gè)問(wèn)題
當(dāng)我用上面的備份策略 完備1-》差備-》日備1-》完備2-》日備2
當(dāng)我完成日備1的時(shí)候,還原界面和backupset表的界面如下
當(dāng)我再進(jìn)行完備2和日備2的時(shí)候,還原界面變成了下面的樣子
backupset表依然能顯示出備份記錄
很多人就認(rèn)為備份鏈斷裂了,日志鏈斷裂,備份日志鏈斷裂,日志備份鏈斷裂
?
這個(gè)表的記錄是刪除不了的
1 USE [msdb] 2 GO 3 DELETE FROM [msdb].[dbo].[backupset] 4 TRUNCATE TABLE [msdb].[dbo].[backupset] View Code 1 消息 547,級(jí)別 16,狀態(tài) 0,第 1 行 2 DELETE 語(yǔ)句與 REFERENCE 約束"FK__backupfil__backu__473C8FC7"沖突。該沖突發(fā)生于數(shù)據(jù)庫(kù)"msdb",表"dbo.backupfilegroup", column 'backup_set_id'。 3 語(yǔ)句已終止。 4 消息 4712,級(jí)別 16,狀態(tài) 1,第 2 行 5 無(wú)法截?cái)啾?'msdb.dbo.backupset',因?yàn)樵摫碚?FOREIGN KEY 約束引用。這個(gè)表記錄了在備份的時(shí)候的lsn號(hào)
可以根據(jù)paul的文章做一些實(shí)驗(yàn)
Debunking a couple of myths around full database backups
?
?
我們做一個(gè)實(shí)驗(yàn),先做一個(gè)完整備份
1 --第一個(gè)完整備份 2 DECLARE @strbackup NVARCHAR(100) 3 --改為日期加時(shí)間的 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 Codebackupset表就會(huì)產(chǎn)生一條記錄
我們將bak文件刪除
用GUI來(lái)還原數(shù)據(jù)庫(kù)
?結(jié)果:
他們的關(guān)系
1 USE [msdb] 2 GO 3 SELECT * FROM [dbo].[backupfile] 4 SELECT * FROM [dbo].[backupfilegroup] 5 SELECT * FROM [dbo].[backupset] 6 SELECT * FROM [sys].[backup_devices] 7 SELECT * FROM [dbo].[backupmediafamily] 8 SELECT * FROM [dbo].[backupmediaset]每次備份的記錄都記錄在這些表里面,還原的時(shí)候SSMS讀取這些表的記錄,讓你勾上幾個(gè)選項(xiàng)就可以還原數(shù)據(jù)庫(kù)了(非常傻瓜)
大家不要以為SQLSERVER在還原數(shù)據(jù)庫(kù)的時(shí)候依靠[msdb].[dbo].[backupset]表的lsn去對(duì)比備份順序
大家可以試想一下:
你的數(shù)據(jù)庫(kù)備份了3次,有3個(gè)備份記錄保存在backupset表
那么當(dāng)你把數(shù)據(jù)庫(kù)分離附加到別的sql實(shí)例的時(shí)候,你也可以還原你之前的備份
為什麼呢??
因?yàn)檫€原的時(shí)候只去數(shù)據(jù)庫(kù)的事務(wù)日志去對(duì)比last lsn,是不依靠外部的其他的數(shù)據(jù)的而且也不需要依靠
如果還不明白的話,大家再看一下我上面貼出來(lái)的圖片吧o(∩_∩)o
總結(jié)
一直以來(lái)本人對(duì)SQLSERVER的備份還原機(jī)制都不是很熟悉,通過(guò)跟宋沄劍的討論讓本人重新認(rèn)識(shí)SQLSERVER的備份、還原
失眠了兩晚,今晚可以吃一個(gè)好的水餃了
?
相關(guān)內(nèi)容:
http://social.technet.microsoft.com/Forums/zh-CN/7e531652-1f00-441b-ae20-871b3e9573c8/sql-server-2005?forum=sqlserverzhchs
http://www.sqlskills.com/blogs/paul/misconceptions-around-the-log-and-log-backups-how-to-convince-yourself/
http://www.sqlskills.com/blogs/paul/more-on-how-much-transaction-log-a-full-backup-includes/
http://www.sqlskills.com/blogs/paul/debunking-a-couple-of-myths-around-full-database-backups/
?
淺談SQL Server中的事務(wù)日志(一)----事務(wù)日志的物理和邏輯構(gòu)架
淺談SQL Server中的事務(wù)日志(五)----日志在高可用和災(zāi)難恢復(fù)中的作用
?
上面的結(jié)論都經(jīng)過(guò)我測(cè)試,希望大家可以指出本人的錯(cuò)處o(∩_∩)o
您們也可以動(dòng)手測(cè)試一下我說(shuō)的是不是真的o(∩_∩)o
如有不對(duì)的地方,歡迎大家拍磚o(∩_∩)o
?
2013-12-7 補(bǔ)充:
大家不要誤解了,數(shù)據(jù)庫(kù)事務(wù)日志截?cái)嗟囊馑疾皇钦f(shuō)把不活動(dòng)日志部分刪除了,而是把這些日志清空了
等待重用,除非你收縮事務(wù)日志,不然這些日志空間(VLF)只會(huì)等待重用
2013-12-8 補(bǔ)充:
還原日志備份的時(shí)候使用restore log 或restore database都是一樣的
而還原差異備份的時(shí)候使用restore log就會(huì)報(bào)錯(cuò)
1 USE master 2 GO 3 --創(chuàng)建數(shù)據(jù)庫(kù) 4 CREATE DATABASE LogChainTest; 5 GO 6 --改為完整恢復(fù)模式 7 ALTER DATABASE LogChainTest SET RECOVERY FULL; 8 GO 9 10 11 -------------------------------------------------------------------- 12 --備份 13 --第一個(gè)完整備份 14 USE master 15 GO 16 DECLARE @strbackup NVARCHAR(100) 17 --改為日期加時(shí)間的 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; 22 GO 23 24 25 26 --第一個(gè)日志備份 27 USE LogChainTest 28 GO 29 CREATE TABLE tt(id INT) 30 INSERT INTO tt 31 SELECT 1 32 DECLARE @strbackup NVARCHAR(100) 33 --改為日期加時(shí)間的 34 SET @strbackup = 'C:\LogChainTest_log1_' 35 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 36 ''), ':', '') + '.bak' 37 BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT; 38 GO 39 40 41 42 --第一個(gè)差異備份 43 USE LogChainTest 44 GO 45 INSERT INTO tt 46 SELECT 2 47 DECLARE @strbackup NVARCHAR(100) 48 --改為日期加時(shí)間的 49 SET @strbackup = 'C:\LogChainTest_diff1_' 50 + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ', 51 ''), ':', '') + '.bak' 52 BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL; 53 GO 54 ------------------------------------------------------------------------ 55 56 57 -------------------------------------------------------------------------- 58 --還原 59 60 61 62 USE master 63 GO 64 --只有完備備份還原才可以移動(dòng)數(shù)據(jù)庫(kù)文件 65 RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131208100145.bak' 66 WITH MOVE 'LogChainTest' TO 'E:\LogChainTest.mdf', 67 MOVE 'LogChainTest_log' TO 'E:\LogChainTest_log.ldf', 68 NORECOVERY ,REPLACE 69 GO 70 71 72 RESTORE LOG LogChainTest FROM DISK='c:\LogChainTest_log1_20131208100151.bak' 73 WITH MOVE 'LogChainTest' TO 'E:\LogChainTest.mdf', 74 MOVE 'LogChainTest_log' TO 'E:\LogChainTest_log.ldf', 75 NORECOVERY 76 GO 77 ------------------------------------------------- 78 RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_log1_20131208100151.bak' 79 WITH MOVE 'LogChainTest' TO 'E:\LogChainTest.mdf', 80 MOVE 'LogChainTest_log' TO 'E:\LogChainTest_log.ldf', 81 NORECOVERY 82 GO 83 84 85 RESTORE LOG LogChainTest FROM DISK='c:\LogChainTest_diff1_20131208100251.bak' 86 WITH MOVE 'LogChainTest' TO 'E:\LogChainTest.mdf', 87 MOVE 'LogChainTest_log' TO 'E:\LogChainTest_log.ldf', 88 RECOVERY 89 GO 90 ---------------------------------------------------------- 91 RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_diff1_20131208100251.bak' 92 WITH MOVE 'LogChainTest' TO 'E:\LogChainTest.mdf', 93 MOVE 'LogChainTest_log' TO 'E:\LogChainTest_log.ldf', 94 RECOVERY 95 GO 96 97 USE [LogChainTest] 98 GO 99 SELECT * FROM [dbo].[tt] View Code?
2016-8-2 補(bǔ)充:
MinLSN是當(dāng)前所有活動(dòng)事務(wù)的開(kāi)始LSN和checkpoint的開(kāi)始LSN中的較小者
MinLSN的作用是記錄當(dāng)前數(shù)據(jù)庫(kù)需要恢復(fù)時(shí),可能回滾的上限
實(shí)例恢復(fù)和介質(zhì)恢復(fù)
實(shí)例恢復(fù)和fn_dblog從minlsn開(kāi)始顯示
bootpage-》數(shù)據(jù)庫(kù)最后一個(gè)checkpoint的lsn-》ldf里面定位到數(shù)據(jù)庫(kù)最后一個(gè)checkpoint開(kāi)始的那條日志記錄-》讀取minlsn
頁(yè)頭最后一次修改LSN(m_lsn)和dbi_checkptLSN進(jìn)行對(duì)比
《SQL Server2008數(shù)據(jù)庫(kù)技術(shù)內(nèi)幕》
?
總結(jié)
以上是生活随笔為你收集整理的您真的理解了SQLSERVER的日志链了吗?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android学习系列(15)--App
- 下一篇: MySQL表结构优化