Pulihkan basis data tidak termasuk data FILESTREAM

20

Konteks
Kami sedang mengembangkan sistem dengan database besar-ish di bagian bawah. Ini adalah database MS SQL yang berjalan pada SQL Server 2008 R2. Ukuran total database adalah sekitar 12 GB.

Dari jumlah tersebut, sekitar 8,5 GB berada dalam satu tabel BinaryContent. Seperti namanya, ini adalah tabel tempat kami menyimpan file sederhana, dalam bentuk apa pun, langsung di dalam tabel sebagai BLOB. Baru-baru ini kami telah menguji kemungkinan untuk memindahkan semua file ini dari database ke sistem file menggunakan FILESTREAM.

Kami melakukan modifikasi yang diperlukan untuk database kami tanpa masalah, dan sistem kami masih berfungsi dengan baik setelah migrasi. The BinaryContentmeja terlihat kira-kira seperti ini:

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]

Dengan semua yang ada di PRIMARYgrup file, kecuali bidang FileBinaryContentyang ada di grup file terpisah FileStreamContentFG.

Skenario
Dari sudut pandang pengembang, kami sering ingin salinan baru dari database dari lingkungan produksi kami, untuk dapat mengerjakan data terbaru. Dalam kasus tersebut, kami jarang tertarik pada file yang disimpan di BinaryContent (sekarang menggunakan FILESTREAM).

Kami memiliki ini hampir berfungsi sesuka kami. Kami mencadangkan basis data, tanpa aliran file seperti ini:

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

Dan kembalikan seperti ini:

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

Ini tampaknya berfungsi dengan baik, dan sistem kami berfungsi selama kami menghindari bagian-bagian yang menggunakan FileBinaryContentbidang tersebut. Misalnya, kami dapat menjalankan kueri berikut tanpa masalah:

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

Secara alami, jika saya berhenti mengomentari baris di atas, termasuk FileContentBinarydalam kueri, saya mendapatkan kesalahan:

Data objek besar (LOB) untuk tabel "dbo.BinaryContent" berada di filegroup offline ("FileStreamContentFG") yang tidak dapat diakses.

Sistem kami menangani file mana konten diatur ke null, jadi apa yang saya suka lakukan adalah sesuatu seperti ini:

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

Tapi ini tentu saja memberi saya kesalahan yang sama seperti di atas. Pada titik ini saya terjebak.

Pertanyaan
Apakah ada cara saya bisa memulihkan database tanpa harus juga mengembalikan semuanya dari FileStreamContentFGgrup file? Baik dengan memperbarui nilai-nilai ke nol seperti yang saya coba di atas, atau default ke nol ketika file hilang atau sesuatu?

Atau mungkin saya mendekati masalah dengan cara yang salah?

Saya pada dasarnya adalah seorang pengembang dan tidak memiliki banyak pengetahuan sebagai DBA, jadi permisi jika saya mengabaikan hal-hal sepele di sini.

Julian
sumber
Bisakah Anda melakukan pemulihan penuh sekali sehingga Anda memiliki beberapa data dari FILEGUP [BinaryContent] dan kemudian melakukan pemulihan filegroup Primer ketika Anda ingin memperbarui itu?
jgardner04
@ jgardner04: sepertinya tidak berhasil. Basis data berakhir dalam keadaan tidak konsisten jika saya pertama kali melakukan pemulihan penuh, diikuti oleh pemulihan cadangan yang hanya berisi grup file Utama (Pesan galat: "Basis data tidak dapat dipulihkan karena log tidak dipulihkan (...) database tidak dapat dibawa online karena diperlukan satu atau lebih langkah KEMBALIKAN " ).
Julian
Apakah akses Anda ke dbo.BinaryContent selalu melalui prosedur yang tersimpan? Berapa banyak yang terlibat?
Mark Storey-Smith
@ MarkStorey-Smith: database sebagian besar diakses menggunakan kueri reguler, melalui NHibernate (baik dari aplikasi web ASP.NET dan aplikasi formulir Windows). Bagaimana itu relevan?
Julian
2
Jika akses Anda melalui prosedur tersimpan, kami dapat menerapkan pendekatan dari ketersediaan sebagian / pengembalian sedikit demi sedikit untuk memeriksa filegroup mana yang sedang online. Sejujurnya, pada 12GB itu benar-benar tidak layak untuk diselesaikan, hanya untuk melakukan pengembalian penuh.
Mark Storey-Smith

Jawaban:

10

Apa yang Anda coba lakukan akan membuat basis data dalam keadaan tidak konsisten (transaksi), sehingga tidak mungkin.

The Partial database Ketersediaan whitepaper adalah panduan referensi yang berguna dan termasuk contoh bagaimana untuk memeriksa apakah meja atau file tertentu yang online. Jika akses data Anda melalui prosedur tersimpan, Anda dapat dengan relatif mudah memasukkan pemeriksaan itu.

Salah satu pendekatan alternatif (tapi agak gila) yang mungkin layak dilihat dalam skenario Anda adalah menyembunyikan tabel dan menggantinya dengan tampilan.

-- 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
Mark Storey-Smith
sumber
5

Anda bisa mengisolasi tabel dengan FILESTREAMdalam database yang terpisah dan membuat referensi ke dalam PRODUCTIONdatabase menggunakan tampilan.

Ini akan memungkinkan Anda melakukan apa yang Anda inginkan tanpa menggunakan peretasan.

Bob
sumber
Ini akan menjadi pendekatan saya, tetapi saya kemudian menghadapi masalah mempertahankan integritas referensial antara database, karena pemicu umumnya tidak didukung dengan tabel filestream: dba.stackexchange.com/questions/58208/…
John J Smith