2025年11月28日 星期五

資料庫的piecemeal回復 - 1


作者:楊先民  
精誠資訊/恆逸教育訓練中心資深講師


※網路引用請註明完整出處


在SQL Server中,常常會因為繁雜的回復步驟而導致有些管理者干脆使用完整資料庫備份,完整資料庫還原的方式復原資料,然而這樣的方式不但速度慢而且讓使用者等待時間增加,本期將要介紹 SQL Server的 piecemeal回復機制。

資料庫備份

一般來說,資料庫備份有分基礎資料庫備份與進階資料庫備份,基礎資料庫備份分為兩種類型,一種是資料庫壞了,要把資料百分百的救回,另一種是資料庫沒壞,例如不小心下 update指令沒有下 where,把全公司人的姓名改成同個名字,這時要將資料回復到下 update指令之前。

通常只要學會這兩種基本型,就可以復原各種 SQL Server可能造成的資料庫問題。

那為何還需要進階的備份還原?

需要進階備份還原,主要還是在,當資料庫很大,有多個資料檔案時,用一般標準的備份還原,要等資料庫全部都好才可以使用,試想如果備份需要花費10個小時,復原不可能只要10分鐘,勢必也要花費10小時才能將資料庫全部救回,其中所花費的等待時間想必是非常久的。

也正因為如此,我們需要一個機制,當有多個資料檔時,您可以慢慢循序、輪流的將資料救回,這樣使用者在詢問時,至少可以回復目前完整的進度,例如有三個資料檔壞掉,不但可以一個一個檔案救回,救回資料的當下,該資料就可以看,而無需等到全部資料檔案都救回,這樣使用者詢問復原進度時,就可以跟使用者說已經復原33%66%之類的(人體 progresss bar)。

 

Piecemeal的種類

而這種進階的資料庫復原方式,就叫做 piecemeal restorepiecemeal的意思就是「逐步地」、「輪流地」意思,也就是慢慢的一個個將檔案還原。

piecemeal restore有分為檔案,以及檔案群組的回復方式,本期介紹的是檔案的 piecemeal restore

不過此種回復方式有個限制,就是不能毀壞 primary data file,也就是副檔名 mdf的資料檔不能毀壞,若是毀壞的話,只能使用標準的資料庫復原了。


Piecemeal的檔案回復順序(多檔案篇)

個人建議管理者,將 piecemeal的回復順序用一個工作日誌記錄下來,這樣之後要回復的話可以按表操課,比較不容易忘東忘西。

我們首先先將環境準備好,我們需要一個資料庫,裡面有四個檔案群組(包含 Primary檔案群組),如下:

CREATE DATABASE [testAdventureworks] ON PRIMARY( NAME=N'testAdventureworks_P',FILENAME = N'C:\myDB\DB\testAdventureworks_P.mdf' ),
FILEGROUP GroupA( NAME=N'testAdventureworks_A',FILENAME = N'C:\myDB\DB\testAdventureworks_A.ndf' ),
FILEGROUP GroupB( NAME=N'testAdventureworks_B',FILENAME = N'C:\myDB\DB\testAdventureworks_B.ndf' ),
FILEGROUP GroupC( NAME=N'testAdventureworks_C',FILENAME = N'C:\myDB\DB\testAdventureworks_C.ndf' )
GO

 

再分別在每個檔案群組上各設定一個資料表,並且塞一些資料進去:

USE testAdventureworks
GO
--在各檔案群組各放一個資料表
CREATE TABLE tbP(c1 INT,c2 nvarchar(10)) ON [PRIMARY]
CREATE TABLE tbA(c1 INT,c2 nvarchar(10)) ON [GroupA]
CREATE TABLE tbB(c1 INT,c2 nvarchar(10)) ON [GroupB]
CREATE TABLE tbC(c1 INT,c2 nvarchar(10)) ON [GroupC]
GO
INSERT testAdventureworks.dbo.tbP VALUES(1,'P')
INSERT testAdventureworks.dbo.tbA VALUES(1,'A')
INSERT testAdventureworks.dbo.tbB VALUES(1,'B')
INSERT testAdventureworks.dbo.tbC VALUES(1,'C')
GO


然後,我們先進行資料庫的完整備份

BACKUP DATABASE testAdventureworks TO DISK=N'C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak' WITH format


接下來,故意把testAdventureworks_B.ndf以及testAdventureworks_C.ndf這兩個檔案破壞,再重新啟動 SQL Server服務。

這時,您已經壞掉兩個檔案,但幸好壞掉的都不是 mdf檔案,所以可以執行我們這期的 piecemeal回復工作。


那準備工作是什麼呢?首先您需要把壞掉的檔案設定成 offline,也就是您必須手動下指令:

 

-- OFFLINE

ALTER DATABASE testAdventureworks

MODIFY FILE

     (name = N'testAdventureworks_B', OFFLINE)

go

 

ALTER DATABASE testAdventureworks

MODIFY FILE

     (name = N'testAdventureworks_C', OFFLINE)

Go

 

至於實務中是哪個檔案壞掉,應該可以透過 SQL Server中的 log或是磁碟陣列的燈號來判斷哪個檔案發生問題,然後再決定該如何救資料庫,選擇一個最佳的救援方式。

設定好之後,就可以把資料庫 online了,使用以下的語法:

ALTER DATABASE testAdventureworks
SET ONLINE


目前您的資料庫應該是可以用了,只是壞掉的檔案依舊是無法使用,所以當您在查詢資料時,壞掉的檔案所屬的資料表依舊是無法使用。

接下來,我們要備份 tail-log,使用以下的指令完成:

BACKUP LOG testAdventureworks
TO DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'
WITH NAME = 'LOG_backupset',
     NO_TRUNCATE
 


這點和標準的備份還原方式是一樣的,只是後來的動作就有所不同了。

看您想要還原哪一個資料檔,可以直接下指令還原,例如我想先還原B,就直接下以下的語法:

RESTORE DATABASE testAdventureworks

     FILE = N'testAdventureworks_B'

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH RECOVERY

 

RESTORE LOG testAdventureworks

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH FILE = 2,

     RECOVERY

 

是的,接完 restore file的指令把 B復原後,把剛才備份的 tail-log回復,這時您的 testAdventureworks_B所屬的資料表就可以看了。

接下來的動作,就有點讓人百思不得其解,因為照正常的理論而言, tail-log應該只要備份一次即可用在兩個資料檔案的復原,但實際上如果您直接下下列的指令回復資料檔,是會無法回復C這個資料檔所屬的資料表的:

RESTORE DATABASE testAdventureworks

     FILE = N'testAdventureworks_C'

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH RECOVERY

 

RESTORE LOG testAdventureworks

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH FILE = 2,

     RECOVERY

 

讓人不解的是,理論上只要備份一次的 tail-log,在 piecemeal 檔案群組回復時,確實是如此,只要備份一次即可,但是在 piecemeal 檔案回復時,無論您要回復幾個檔案,皆要再做一次 tail-log備份。也就是接下來的指令是如下的:

--再做一次 tail-log備份

BACKUP LOG testAdventureworks

TO DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH NAME = 'LOG_backupset',

     NO_TRUNCATE


RESTORE DATABASE testAdventureworks

     FILE = N'testAdventureworks_C'

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH RECOVERY


--使用新的 tail-log備份進行還原

RESTORE LOG testAdventureworks

FROM DISK ='C:\myDB\Backup\testAdventureworks_PiecemealBackup.bak'

WITH FILE = 3,

     RECOVERY

 

這個其實讓人不解,因為BC這兩個檔案同時壞掉,而 tail-log在備份時確實時間點並無不同,但是還是得再做一次 tail-log備份,所以這個就當做是一個經驗,把它記下來吧!

就此,您已經完成了 piecemeal 資料檔的復原!

 

 

0 意見:

張貼留言