Datenbank ohne FILESTREAM-Daten wiederherstellen


20

Ausgangssituation
Wir entwickeln ein System mit einer umfangreichen Datenbank im unteren Bereich. Es ist eine MS SQL-Datenbank, die unter SQL Server 2008 R2 ausgeführt wird. Die Gesamtgröße der Datenbank beträgt ca. 12 GB.

Von diesen befinden sich ungefähr 8,5 GB in einer einzelnen Tabelle BinaryContent. Wie der Name schon sagt, ist dies eine Tabelle, in der wir einfache Dateien aller Art direkt als BLOB in der Tabelle speichern. Kürzlich haben wir die Möglichkeit getestet, alle diese Dateien mit FILESTREAM aus der Datenbank in das Dateisystem zu verschieben.

Wir haben die notwendigen Änderungen an unserer Datenbank ohne Probleme vorgenommen und unser System funktioniert auch nach der Migration noch einwandfrei. Die BinaryContentTabelle sieht ungefähr so ​​aus:

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]

Alles, was sich in der PRIMARYDateigruppe befindet, mit Ausnahme des Felds, FileBinaryContentdas sich in einer separaten Dateigruppe befindet FileStreamContentFG.

Szenario
Aus Entwicklersicht möchten wir häufig eine neue Kopie der Datenbank aus unserer Produktionsumgebung, um die neuesten Daten verarbeiten zu können. In diesen Fällen interessieren uns die in BinaryContent (jetzt mit FILESTREAM) gespeicherten Dateien nur selten .

Wir haben dies fast so, wie wir möchten. Wir sichern die Datenbank ohne den folgenden Dateistream:

BACKUP DATABASE FileStreamDB
FILEGROUP = 'PRIMARY' 
TO DISK = 'c:\backup\FileStreamDB_WithoutFS.bak' WITH INIT

Und stellen Sie es wie folgt wieder her:

RESTORE DATABASE FileStreamDB
FROM DISK = 'c:\backup\FileStreamDB_WithoutFS.bak'

Dies scheint in Ordnung zu sein, und unser System funktioniert, solange wir die Teile meiden, die das FileBinaryContentFeld verwenden. Wir können zum Beispiel die folgende Abfrage problemlos ausführen:

SELECT TOP 10 [BinaryContentID],[FileName],[BinaryContentRowGUID]
--,[FileContentBinary]
FROM [dbo].[BinaryContent]

Wenn ich die obige Zeile einschließlich FileContentBinaryder Abfrage auskommentiere, erhalte ich natürlich eine Fehlermeldung:

LOB-Daten (Large Object) für die Tabelle "dbo.BinaryContent" befinden sich in einer Offlinedateigruppe ("FileStreamContentFG"), auf die nicht zugegriffen werden kann.

Unser System verarbeitet Dateien, auf die der Inhalt eingestellt ist. nullIch möchte also Folgendes tun:

UPDATE [dbo].[BinaryContent]
SET [FileContentBinary] = null

Aber das gibt mir natürlich den gleichen Fehler wie oben. An diesem Punkt stecke ich fest.

Frage
Kann ich die Datenbank auf irgendeine Weise wiederherstellen, ohne auch alles aus der FileStreamContentFGDateigruppe wiederherstellen zu müssen ? Entweder durch Aktualisieren der Werte auf Null, wie ich es oben versuche, oder standardmäßig auf Null, wenn die Datei fehlt oder so?

Oder gehe ich das Problem vielleicht falsch an?

Ich bin von Natur aus ein Entwickler und habe nicht viel Wissen als DBA. Entschuldigen Sie mich, wenn ich hier etwas Triviales übersehen habe.


Könnten Sie die vollständige Wiederherstellung einmal durchführen, damit Sie einige Daten aus der [BinaryContent] -DATEIGRUPPE haben, und dann eine Wiederherstellung der primären Dateigruppe durchführen, wenn Sie sie aktualisieren möchten?
jgardner04

@ jgardner04: das scheint nicht zu funktionieren. Die Datenbank befindet sich in einem inkonsistenten Zustand, wenn ich zuerst eine vollständige Wiederherstellung durchführe, gefolgt von einer Wiederherstellung der Sicherung, die nur die primäre Dateigruppe enthält (Fehlermeldung: "Die Datenbank kann nicht wiederhergestellt werden, da das Protokoll nicht wiederhergestellt wurde (...) Die Datenbank konnte nicht online geschaltet werden, da ein oder mehrere RESTORE - Schritte erforderlich sind " ).
Julian

Greifen Sie immer über gespeicherte Prozeduren auf dbo.BinaryContent zu? Wie viele sind beteiligt?
Mark Storey-Smith

@ MarkStorey-Smith: Auf die Datenbank wird hauptsächlich mit regulären Abfragen über NHibernate zugegriffen (sowohl von einer ASP.NET-Webanwendung als auch von einer Windows Forms-Anwendung). Wie ist das relevant?
Julian

2
Wenn Ihr Zugriff über gespeicherte Prozeduren erfolgte, könnten wir einen Ansatz aus Teilverfügbarkeit / Teilwiederherstellung anwenden, um zu überprüfen, welche Dateigruppen online sind. Um ehrlich zu sein, ist es bei 12 GB wirklich nicht wert, herumzuarbeiten, nur um die vollständige Wiederherstellung durchzuführen.
Mark Storey-Smith

Antworten:


10

Was Sie versuchen, würde die Datenbank in einem (transaktionsbedingt) inkonsistenten Zustand belassen, daher ist dies nicht möglich.

Das Whitepaper zur Verfügbarkeit von Teildatenbanken ist ein nützliches Referenzhandbuch und enthält ein Beispiel für die Überprüfung, ob eine bestimmte Tabelle oder Datei online ist. Wenn Ihr Datenzugriff über gespeicherte Prozeduren erfolgt, können Sie diese Prüfung relativ einfach einbauen.

Ein alternativer (aber etwas hackiger) Ansatz, der in Ihrem Szenario einen Blick wert sein könnte, besteht darin, die Tabelle auszublenden und durch eine Ansicht zu ersetzen.

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

Sie können die Tabelle mit einem FILESTREAMin einer separaten Datenbank isolieren und PRODUCTIONmithilfe einer Ansicht einen Verweis auf sie in der Datenbank erstellen .

Auf diese Weise können Sie tun, was Sie möchten, ohne auf Hacks zurückgreifen zu müssen.


Dies sollte mein Ansatz sein, aber dann stieß ich auf Probleme bei der Aufrechterhaltung der referenziellen Integrität zwischen den Datenbanken, da Trigger in der Regel nicht von Dateistream-Tabellen unterstützt werden: dba.stackexchange.com/questions/58208/…
John J Smith
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.