SQL Server 的備份與恢復
Backup和restore: SQL Server的備份有三種形式:一是全備份(full backup), 這個備份裡面包含的內容是值得商榷的,我們知道資料庫有兩種檔案,資料檔案與日誌檔案,全備份是不是將所有的資料檔案與日誌檔案打包,備份成一個檔案? 那麼還原的時候是不是需要做恢復,將備份過後發生的事務接著備份時間點重新執行一邊? 上面的問題細想都是肯定的。全備份做的事情,就是將所有的快取先flush到磁碟上,不管在進行的事務是否提交,這樣保證了日誌的連續性,資料與日誌的一致性,如果事務沒提交 ,在日誌檔案上的標記是active的,這段日誌也就不會被清空,下次恢復的時候,就從這段日誌開始,接著使用新的日誌執行。因此 全備份之前肯定會執行一次checkpoint;二是差異備份(differential backup),
全備份:
全備份用到的命令,涉及到兩方面的引數,一是指定相應的備份裝置,可以是磁碟,也可以是磁帶;另一方面 就是備份可用的選項,比如是否壓縮,是否加密。
BACKUP DATABASE database
TO backup_device [ ,...n ][ WITH with_options [ ,...o ] ] ;
備份裝置很講究,可以事先定義好邏輯裝置,也可以直接指定物理裝置。磁帶備份機倒是沒見過,但是常規的磁碟備份還是可以討論一下的:
我們可以將一個本機帶路徑的物理檔名指定為備份裝置:
backup database lenistest
to disk = 'E :\Data_BU\lenistest5__backup.bck' ;
也可以將網路上的一個帶路徑的物理檔名指定為備份裝置:
BACKUP DATABASE AdventureWorks2012
TO DISK = '\\BackupSystem\BackupDisk1\AW_backups\AdventureWorksData.Bak';
GO
這裡有個有趣的現象,如果我們在全備份之後 ,沒有備份好日誌,這個時候故障突然發生了,我們需要作恢復,但是恢復的時候因為會重寫日誌,這樣就會丟失資料,如果不採取額外地措施,系統是會報錯的:
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup.bck'
Msg 3159, Level 16, State 1, Line 6
The tail of the log for the database “lenistest” has not been backed
up. Use BACKUP LOG WITH NORECOVERY to backup the log if it contains
work you do not want to lose. Use the WITH REPLACE or WITH STOPAT
clause of the RESTORE statement to just overwrite the contents of the
log.Msg 3013, Level 16, State 1, Line 6
RESTORE DATABASE is terminating abnormally.
所以如果對丟失的資料不關心或者認為不會丟失資料,可以採用with replace選項來重寫原來的日誌檔案進行強制恢復。
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup.bck'
with replace ;
差異備份:
差異備份相對全備份,優越的地方在於備份資料量少,但是有趣的是差異備份不能獨立存在(日誌備份也不能獨立存在,他倆只能依附於全備份,也就是說在執行差異備份和日誌備份的時候,必須先有一個全備份做好在那裡), 差異備份必須以一個全備份做基準,在這基礎之上再判斷哪些資料頁是有過更新的,這些更新的資料頁計算出來並被備份起來。
use master
go
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup.bck' ;
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup.bck'
with differential ;
假如我們沒有事先做好全備份,就直接作差異備份了,那麼這是不成功的:
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup2.bck'
with differential ;
Msg 3035, Level 16, State 1, Line 11
Cannot perform a differential backup for database “lenistest”, because
a current database backup does not exist. Perform a full database
backup by reissuing BACKUP DATABASE, omitting the WITH DIFFERENTIAL
option.Msg 3013, Level 16, State 1, Line 11
BACKUP DATABASE is terminating abnormally.
日誌備份:
日誌備份相對差異備份來說,體量更小,同樣它也需要全備份事先存在:
backup log lenistest
to disk = 'E:\Data_BU\lenistest5__backup.bck';
假如我沒有事先做好全備份,我們看看直接備份日誌會出現什麼結果:
Msg 4214, Level 16, State 1, Line 15
BACKUP LOG cannot be performed because there is no current database
backup.Msg 3013, Level 16, State 1, Line 15
BACKUP LOG is terminating abnormally.
提示先做全備份!
備份我們都討論完了,接下來我們看看還原。還原通常有兩個步驟,一是還原,二是恢復。當然我們也可以直接還原不恢復,但是可能會丟失資料,除非全備份之後 ,沒有任何操作。假設我們一天一個全備份,每15分鐘做一個差異備份 ,每5分鐘做一個日誌備份,我們該如何還原我們的資料庫呢?
通常我們首先要知道我們的備份檔名或者物理路徑,這個地方涉及到很多術語很難理解,比如說backup device, backupset, backup media, media set ,media family.
MSDN上有一個解釋,先看這個指令碼:
BACKUP DATABASE AdventureWorks2012
TO TAPE = '\\.\tape0', TAPE = '\\.\tape1', TAPE = '\\.\tape2'
WITH
FORMAT,
MEDIANAME = 'MyAdvWorks_MediaSet_1'
解釋說到,這個備份操作產生了一個 media set, 這個media set就是命名為MyAdvWorks_MediaSet_1, 這個media set還有個media header, media header一旦生成,就可以往裡面寫入備份檔案了。這段指令碼也同時生成了一個橫跨三個tape的備份檔案, 他們統稱為backup set.
當我們指定3個backup device作為backup set(備份集)並且執行第一次全備份的時候,接下來所有的備份都需要同時指定這3個backup device作為backup set:
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck'
with format, medianame = 'lenistestbackupset' ;
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck'
with noinit, differential, medianame = 'lenistestbackupset' ;
Msg 3231, Level 16, State 1, Line 10
The media loaded on “E:\Data_BU\lenistest5__backup01.bck” is formatted
to support 3 media families, but 2 media families are expected
according to the backup device specification.Msg 3013, Level 16, State 1, Line 10
BACKUP DATABASE is terminating abnormally.
上面我先作了一次全備份,指定了三個backup device作為一份backup set, 接下來作差異備份的時候,我只指定了其中兩個backup device作為backup set, 操作失敗,提示就是少了一個backup device.
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with noinit, differential, medianame = 'lenistestbackupset' ;
這次我們指定了同樣個數的backup device,但backup device的順序顛倒了一下,操作成功。
到目前為止,我們的指令碼已經新建了 1 個media set,名為 lenistestbackupset , 2 個backup set, 第一個backup set是全備份的backup set,另外一個backup set是差異備份。所以每一次備份都會產生一個backup set. Media set產生的時間則是第一次給資料庫作全備份的時候。
這個時候我們需要恢復資料庫,那麼第一步就是要先還原全備份,但是先不恢復,等全備份還原過後,再用差異備份做恢復:
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 1 , replace, norecovery ;
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 2 , recovery ;
這裡一定是用replace來重寫日誌。
select mf.media_set_id
,isnull(ms.name,'no media name') as media_name
,mf.physical_device_name
,mf.family_sequence_number
,mf.media_family_id
,bs.database_name
,bs.backup_start_date
,bs.backup_finish_date
from backupmediafamily mf
inner join backupset bs on mf.media_set_id = bs.media_set_id
left join backupmediaset ms on bs.media_set_id = ms.media_set_id
where bs.database_name = 'lenistest'
上面的指令碼可以抓出來這些media family, media set, backup set的資訊,如果像上面的例子一樣, 我們用3個backup device來承載備份,那麼這3個backup device組成了一個media family, 按照family_sequence_number來編排,1,2,3。
下面實現一個備份到恢復的全過程例子,分別在full backup, differential backup, log backup之前各出入同樣的資料,看看是不是還原的時候,能正確還原過來:
insert into dbo.dataloading(object_id,object_name)
select object_id, name as object_name
from sys.objects
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck'
with format, medianame = 'lenistestbackupset' ;
go
insert into dbo.dataloading(object_id,object_name)
select object_id, name as object_name
from sys.objects
backup database lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with noinit, differential, medianame = 'lenistestbackupset' ;
go
insert into dbo.dataloading(object_id,object_name)
select object_id, name as object_name
from sys.objects
backup log lenistest
to disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with noinit, medianame = 'lenistestbackupset' ;
接著我們做還原與恢復:
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 1 , replace, norecovery ;
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 2 , norecovery ;
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 3 , recovery ;
這裡的file選項就是backup set選項,表示第一個備份集,第二個備份集,第三個備份集。如果想還原到最新的故障發生時間點,前面的restore都不能recovery,只有在最後的時候才能作recovery.
如果我們只想恢復全備份的資料,只要執行recovery就可以了,但是資料肯定是少了:
restore database lenistest
from disk = 'E:\Data_BU\lenistest5__backup01.bck', disk = 'E:\Data_BU\lenistest5__backup03.bck', disk = 'E:\Data_BU\lenistest5__backup02.bck'
with file = 1 , replace, recovery ;
歡迎關注個人微信公眾號