解決 SQL Server 備份到 FAT32 磁區失敗的問題 (兼談 BACKUP 指令)

解決 SQL Server 備份到 FAT32 磁區失敗的問題 (兼談 BACKUP 指令)

現在的 Flash 隨身碟不僅容量大又便宜,根據 7/25 最新報價,各大品牌 16GB 隨身碟價格普遍落在 1000 至 1500 新台幣之間,加上易插拔、隨身攜帶等特性,堪稱 IT 人員不可或缺的廉價「異地備援」解決方案,要說是玩不起高級設備的小公司生存之道也不誇張,因為前兩天我老闆就拿了一支 16 GB 隨身碟接到 DB 伺服器上,跟我說他想將資料庫備份到隨身碟,但一直出現『磁碟空間不足』的錯誤…

其實我們公司的資料庫不大,完整備份的檔案大小約 7GB,試了一下備份指令卻真的會出現錯誤:
TO DISK = N'J:\db.bak'
WITH NOFORMAT,
	INIT,
	SKIP,
	NAME = 'db',
	MEDIANAME = 'db',
	MEDIADESCRIPTION = 'Complete Backup for [db] database',
	STATS = 10;
GO
	
/*
	訊息 3202,層級 16,狀態 2,行 1
	寫入 "J:\db.bak" 失敗: 112(磁碟的空間不足。)
	訊息 3013,層級 16,狀態 1,行 1
	BACKUP DATABASE 正在異常結束。
*/
乍看會覺得納悶,明明有 16 GB 的容量怎麼塞不到一半就說磁碟空間不足?

我下的指令有 STATS = 10 這個選項,每完成 10% 會回報處理進度,最後一次回報是停在百分之 60,再去查看隨身碟的實際空間是 14.9 GB,檔案系統格式是 FAT32…等等!我記得 FAT32 有單一檔案不得超過 4GB 的限制,問題八成就在這兒了,我想只要重新格式化成 NTFS 應該能解決,但實際要新格式化為 NTFS 時卻沒這個選項…

sandisk_cruzer_blade_16gb 

山不轉路轉,好在 SQL Server 可以做到等量備份,將備份檔等量切分成多個實體檔案,就是所謂的等量媒體集備份裝置 (Striped Media Set),實際指令如下:
TO DISK = N'J:\db_part1.bak',
	DISK = N'J:\db_part2.bak',
	DISK = N'J:\db_part3.bak'
WITH FORMAT,
	NAME = 'db_StripedSet',
	MEDIANAME = 'db_StripedSet',
	MEDIADESCRIPTION = 'Striped media set for [db] database completely backup',
	STATS = 10;
GO
值得一提的是,我的需求主要是要讓單一檔案大小不超過 4GB,所以寫入效率就不那麼要求,實際上若有多顆實體磁碟,寫入位置可以分別指定到不同磁碟,此時會有類似磁碟陣列 RAID 0 的加速效果。

寫到這裡,順便連備份指令的其他用法也紀錄一下好了。有在玩磁碟陣列的人應該也知道鏡像備份 (RAID 1),SQL Server 的備份指令也有類似的概念,稱之為鏡像媒體集 (Mirrored Media Set),寫法可以參考底下指令:
TO DISK = N'X:\db.bak'
-- 兩份鏡像
MIRROR TO DISK = N'Y:\db.bak'
MIRROR TO DISK = N'Z:\db.bak'
WITH FORMAT,
	NAME = 'db',
	MEDIANAME = 'db',
	MEDIADESCRIPTION = 'Backup for [db] database',
	STATS = 10;
GO
此時除了原本的備份路徑,還會同時複寫到所有 MIRROR TO 的指定裝置,且擁有一模一樣的內容,其中最多可以包含四個鏡像 (MIRROR TO 出現 3 次),好處是不需要額外做檔案複製搬移,需留存多個備份檔在不同地方的話可以考慮這種做法。

最後則是以上兩者混用,概念上很像 RAID 0+1, 例如 SQL Server 線上叢書的範例:
TO DISK='X:\SQLServerBackups\AdventureWorks2008R2_1a.bak', 
	DISK='Y:\SQLServerBackups\AdventureWorks2008R2_2a.bak', 
	DISK='Z:\SQLServerBackups\AdventureWorks2008R2_3a.bak'
MIRROR TO DISK='X:\SQLServerBackups\AdventureWorks2008R2_1b.bak', 
	DISK='Y:\SQLServerBackups\AdventureWorks2008R2_2b.bak', 
	DISK='Z:\SQLServerBackups\AdventureWorks2008R2_3b.bak';
GO
這個備份指令做了 3 個一組的等量切分,並且附加一份鏡像。這邊要提醒大家,此範例是為了方便在本機測試,實際上在單一磁碟寫入多個備份會降低效能,而且可能會減損鏡像媒體集原先設計的備援性,若是指定 UNC 路徑存放到 File Server 上會比較恰當,還有使用上要特別注意每個 MIRROR TO 子句都必須列出與 TO 子句相同的裝置數目和類型。

以上大概介紹了 BACKUP 指令的幾種用法,至於細節就請大家自行參閱 SQL Server 線上叢書囉!


參考連結