还原数据库(不包括FILESTREAM数据)


20

背景
我们正在开发一个系统,该系统的底部有一个大型数据库。它是在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的知识,所以如果我在这里忽略了一些琐碎的事情,请原谅我。


您能否进行一次完整还原,以便从[BinaryContent] FILEGROUP中获得一些数据,然后在想要更新主文件组时进行还原?
jgardner04年

@ jgardner04:似乎不起作用。如果首先执行完整还原,然后还原仅包含主文件组的备份,则数据库将以不一致的状态结束(错误消息:“由于未还原日志,因此无法还原数据库(...)该数据库无法联机,因为需要执行一个或多个RESTORE步骤”)。
朱利安

您是否总是通过存储过程访问dbo.BinaryContent?涉及多少?
Mark Storey-Smith

@ MarkStorey-Smith:主要通过NHibernate(均来自ASP.NET Web应用程序和Windows窗体应用程序)使用常规查询访问数据库。那有什么关系?
朱利安

2
如果您通过存储过程进行访问,我们可以采用从部分可用性/逐件还原的方法来检查哪些文件组处于联机状态。老实说,只有12GB的存储容量才值得完全恢复。
Mark Storey-Smith

Answers:


10

您尝试执行的操作会使数据库处于(事务性)不一致状态,因此这是不可能的。

部分数据库可用性”白皮书是有用的参考指南,并提供了有关如何检查特定表或文件是否在线的示例。如果您的数据访问是通过存储过程进行的,则可以相对轻松地合并该检查。

在您的方案中可能值得一看的另一种方法(但有些怪异)是隐藏表并将其替换为视图。

-- 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

5

您可以FILESTREAM在单独的数据库中用隔离表,并PRODUCTION使用视图在数据库中创建对该表的引用。

这样一来,您就可以在不诉诸黑客的情况下做自己想做的事情。


这将是我的做法,但后来我碰到了维护数据库之间的引用完整性的问题,因为触发一般不与FILESTREAM表支持:dba.stackexchange.com/questions/58208/...
约翰·史密斯Ĵ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.