กู้คืนฐานข้อมูลไม่รวมข้อมูล FILESTREAM


20

บริบท
เรากำลังพัฒนาระบบที่มีฐานข้อมูลขนาดใหญ่ที่ด้านล่าง มันเป็นฐานข้อมูล MS SQL ที่ทำงานบน SQL Server 2008 R2 ขนาดทั้งหมดของฐานข้อมูลประมาณ 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กลุ่มของแฟ้มยกเว้นเขตที่อยู่ในกลุ่มแฟ้มแยกต่างหากFileBinaryContentFileStreamContentFG

สถานการณ์
จากมุมมองของนักพัฒนาเรามักต้องการสำเนาใหม่ของฐานข้อมูลจากสภาพแวดล้อมการผลิตของเราเพื่อให้สามารถทำงานกับข้อมูลล่าสุดได้ ในกรณีเหล่านี้เราไม่ค่อยสนใจไฟล์ที่จัดเก็บใน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ในแบบสอบถามฉันได้รับข้อผิดพลาด:

ข้อมูลวัตถุขนาดใหญ่ (LOB) สำหรับตาราง "dbo.BinaryContent" ตั้งอยู่ในกลุ่มออฟไลน์ไฟล์ ("FileStreamContentFG") ที่ไม่สามารถเข้าถึงได้

ไฟล์ที่มีเนื้อหาถูกตั้งค่าให้จับระบบของเราnullดังนั้นสิ่งที่ผมจะชอบที่จะทำคืออะไรเช่นนี้

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

แต่แน่นอนว่านี่ทำให้ฉันมีข้อผิดพลาดเหมือนข้างต้น ณ จุดนี้ฉันติดอยู่

คำถาม
มีวิธีใดบ้างที่ฉันสามารถกู้คืนฐานข้อมูลโดยไม่ต้องกู้คืนทุกอย่างจากFileStreamContentFGกลุ่มไฟล์ได้ อย่างใดอย่างหนึ่งโดยการปรับปรุงค่าเป็นโมฆะในขณะที่ฉันพยายามด้านบนหรือเริ่มต้นที่โมฆะเมื่อไฟล์หายไปหรืออะไร

หรือฉันกำลังเข้าใกล้ปัญหาในทางที่ผิด?

ฉันเป็นนักพัฒนาโดยธรรมชาติและไม่มีความรู้ในฐานะ DBA มากนักดังนั้นขอยกโทษให้ฉันถ้าฉันมองไปที่สิ่งเล็ก ๆ น้อย ๆ ที่นี่


คุณสามารถทำการกู้คืนแบบเต็มครั้งเดียวเพื่อให้คุณมีข้อมูลบางส่วนจาก [BinaryContent] FILEGROUP แล้วทำการกู้คืนกลุ่มไฟล์หลักเมื่อคุณต้องการอัปเดตหรือไม่
jgardner04

@ jgardner04: ดูเหมือนจะไม่ทำงาน ฐานข้อมูลสิ้นสุดลงในสถานะไม่สอดคล้องกันถ้าฉันทำการกู้คืนแบบเต็มครั้งแรกตามด้วยการคืนค่าการสำรองข้อมูลที่มีเฉพาะกลุ่มไฟล์หลัก (ข้อความแสดงข้อผิดพลาด: "ฐานข้อมูลไม่สามารถกู้คืนได้เนื่องจากบันทึกไม่ถูกกู้คืน (... ) ไม่สามารถนำฐานข้อมูลออนไลน์ได้เนื่องจากจำเป็นต้องมีขั้นตอน RESTORE หนึ่งขั้นหรือมากกว่า " )
Julian

การเข้าถึง dbo.BinaryContent ของคุณผ่านขั้นตอนการจัดเก็บเสมอหรือไม่ มีผู้เกี่ยวข้องกี่คน
Mark Storey-Smith

@ MarkStorey-Smith: ฐานข้อมูลส่วนใหญ่เข้าถึงได้โดยใช้แบบสอบถามปกติผ่าน NHibernate (ทั้งจากเว็บแอปพลิเคชัน ASP.NET และแอปพลิเคชันฟอร์ม Windows) มีความเกี่ยวข้องกันอย่างไร
Julian

2
หากการเข้าถึงของคุณผ่านขั้นตอนการจัดเก็บเราสามารถใช้วิธีการจากความพร้อมใช้งาน / การกู้คืนทีละส่วนเพื่อตรวจสอบว่ากลุ่มไฟล์ใดบ้างที่ออนไลน์ ความจริงแล้วที่ขนาด 12GB นั้นไม่คุ้มที่จะหลีกเลี่ยงเพียงทำการคืนค่าอย่างเต็มรูปแบบ
Mark Storey-Smith

คำตอบ:


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

คุณสามารถแยกตารางด้วย a FILESTREAMในฐานข้อมูลแยกต่างหากและสร้างการอ้างอิงถึงมันในPRODUCTIONฐานข้อมูลโดยใช้มุมมอง

สิ่งนี้จะช่วยให้คุณทำสิ่งที่คุณต้องการโดยไม่ต้องแฮ็ค


นี่จะเป็นแนวทางของฉัน แต่ฉันก็พบปัญหาการรักษาความสมบูรณ์ของการอ้างอิงระหว่างฐานข้อมูลเนื่องจากทริกเกอร์มักไม่รองรับตาราง filestream: dba.stackexchange.com/questions/58208/ …
John J Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.