恢復不包括 FILESTREAM 數據的數據庫
上下文
我們正在開發一個底層有一個大型數據庫的系統。它是一個執行在 SQL Server 2008 R2 上的 MS SQL 數據庫。數據庫的總大小約為 12 GB。
其中,大約 8.5 GB 位於單個表中
BinaryContent
。顧名思義,這是一個表,我們將任何類型的簡單文件作為 BLOB 直接儲存在表中。最近,我們一直在測試使用 FILESTREAM 將所有這些文件從數據庫移到文件系統的可能性。我們對數據庫進行了必要的修改,沒有任何問題,遷移後我們的系統仍然可以正常工作。該
BinaryContent
表大致如下所示:CREATE TABLE [dbo].[BinaryContent]( [BinaryContentID] [int] IDENTITY(1,1) NOT NULL, [FileName] [varchar](50) NOT NULL, [BinaryContentRowGUID] [uniqueidentifier] ROWGUIDCOL NOT NULL ) ON [PRIMARY] FILESTREAM_ON [FileStreamContentFG] ALTER TABLE [dbo].[BinaryContent] ADD [FileContentBinary] [varbinary](max) FILESTREAM NULL ALTER TABLE [dbo].[BinaryContent] ADD CONSTRAINT [DFBinaryContentRowGUID] DEFAULT (newsequentialid()) FOR [BinaryContentRowGUID]
所有內容都位於文件組中,但位於單獨文件組中
PRIMARY
的欄位除外。FileBinaryContent``FileStreamContentFG
場景
從開發人員的角度來看,我們通常希望從生產環境中獲取數據庫的新副本,以便能夠處理最新數據。在這些情況下,我們很少對儲存在BinaryContent(現在使用 FILESTREAM)中的文件感興趣。
我們幾乎可以隨心所欲地工作。我們備份數據庫,沒有這樣的文件流:
BACKUP DATABASE FileStreamDB FILEGROUP = 'PRIMARY' TO DISK = 'c:\backup\FileStreamDB_WithoutFS.bak' WITH INIT
並像這樣恢復它:
RESTORE DATABASE FileStreamDB FROM DISK = 'c:\backup\FileStreamDB_WithoutFS.bak'
這似乎工作正常,只要我們避免使用該
FileBinaryContent
欄位的部分,我們的系統就可以正常工作。例如,我們可以毫無問題地執行以下查詢:SELECT TOP 10 [BinaryContentID],[FileName],[BinaryContentRowGUID] --,[FileContentBinary] FROM [dbo].[BinaryContent]
自然,如果我取消註釋上面的行,包括
FileContentBinary
在查詢中,我會收到一個錯誤:表“dbo.BinaryContent”的大對象 (LOB) 數據位於無法訪問的離線文件組 (“FileStreamContentFG”) 上。
我們的系統處理內容設置為 的文件
null
,所以我想做的是這樣的:UPDATE [dbo].[BinaryContent] SET [FileContentBinary] = null
但這當然給了我與上面相同的錯誤。在這一點上,我被困住了。
問題
有什麼方法可以還原數據庫而不必從
FileStreamContentFG
文件組中還原所有內容?通過在上面嘗試將值更新為 null ,或者在文件失去時預設為 null 或其他什麼?還是我可能以錯誤的方式解決問題?
我天生就是一名開發人員,作為 DBA 沒有太多知識,所以如果我在這裡忽略了一些瑣碎的事情,請原諒。
您嘗試做的事情會使數據庫處於(事務性)不一致狀態,因此這是不可能的。
部分數據庫可用性白皮書是一份有用的參考指南,其中包括一個如何檢查特定表或文件是否線上的範例。如果您的數據訪問是通過儲存過程進行的,那麼您可以相對輕鬆地合併該檢查。
在您的場景中可能值得一看的一種替代方法(但有些笨拙)是隱藏表格並用視圖替換它。
-- NB: SQLCMD script :ON ERROR EXIT :setvar DatabaseName "TestRename" :setvar FilePath "D:\MSSQL\I3\Data\" SET STATISTICS TIME OFF; SET STATISTICS IO OFF; SET NOCOUNT ON; GO USE master; GO IF EXISTS (SELECT name FROM sys.databases WHERE name = N'$(DatabaseName)') DROP DATABASE $(DatabaseName) GO CREATE DATABASE $(DatabaseName) ON PRIMARY ( NAME = N' $(DatabaseName)' , FILENAME = N'$(FilePath)$(DatabaseName).mdf' , SIZE = 5MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB ) , FILEGROUP [FG1] DEFAULT ( NAME = N' $(DatabaseName)_FG1_File1' , FILENAME = N'$(FilePath)$(DatabaseName)_FG1_File1.ndf' , SIZE = 1MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB ) , FILEGROUP [FG2] CONTAINS FILESTREAM ( NAME = N'$(DatabaseName)_FG2' , FILENAME = N'$(FilePath)Filestream' ) LOG ON ( NAME = N'$(DatabaseName)_log' , FILENAME = N'$(FilePath)$(DatabaseName)_log.ldf' , SIZE = 1MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB ) GO USE $(DatabaseName); GO CREATE TABLE [dbo].[BinaryContent]( [BinaryContentID] [int] IDENTITY(1,1) NOT NULL , [FileName] [varchar](50) NOT NULL , [BinaryContentRowGUID] [uniqueidentifier] ROWGUIDCOL UNIQUE DEFAULT (NEWSEQUENTIALID()) NOT NULL , [FileContentBinary] VARBINARY(max) FILESTREAM NULL ) ON [PRIMARY] FILESTREAM_ON [FG2] GO -- Insert test rows INSERT dbo.BinaryContent ( [FileName] , [FileContentBinary] ) VALUES ( CAST(NEWID() AS VARCHAR(36)) , CAST(REPLICATE(NEWID(), 100) AS VARBINARY) ); GO 100 USE master; GO -- Take FILESTREAM filegroup offline ALTER DATABASE $(DatabaseName) MODIFY FILE (NAME = '$(DatabaseName)_FG2', OFFLINE) GO USE $(DatabaseName); GO -- Rename table to make way for view EXEC sp_rename 'dbo.BinaryContent', 'BinaryContentTable', 'OBJECT'; GO -- Create view to return content from table but with NULL FileContentBinary CREATE VIEW dbo.BinaryContent AS SELECT [BinaryContentID] , [FileName] , [BinaryContentRowGUID] , [FileContentBinary] = NULL FROM [dbo].[BinaryContentTable]; GO -- Check results as expected SELECT TOP 10 * FROM dbo.BinaryContent; GO