web-dev-qa-db-ja.com

ファイルの復元で予期しない結果

AdventureWorksデータベースを使用してファイルの復元を実行していますが、期待した復元が得られません。恥ずかしいほど単純な原因があると思いますが、まだ見つけていません。

これが私がしたことです

  1. USERTABLES_01という名前の新しいファイルグループを作成しました。
  2. HumanResources.EmployeeテーブルからHumanResources.Employee_01ファイルグループの新しい.USERTABLES_01にデータをコピーしました。
  3. フルバックアップを生成しました。
  4. Where句なしでDELETE FROM HumanResources.Employee_01を実行しました
  5. Shazbot 、テーブルを復元する必要があります。 OK、ファイルグループUSERTABLES_01を復元します。
  6. 実行されたRESTORE DATABASE [AdventureWorks2012] FILE N'AdventureWorks2012_UserTables_01'.。
  7. テールログバックアップを生成しました
  8. 復元されたテールログバックアップ

すべてが文句なしに復元されます。しかし、私のHumanResources.Employee_01にはデータがありません。

レビュー MSの例 、おそらく私はそれを正しくフォローしていませんでしたが、私はかなり従ったと確信しています。

同様の質問を確認しましたが、それが私が探している答えであるかどうかはわかりません: SQL Serverのファイルグループの.mdfデータファイルを復元する

2
Mike Henderson

SQL Serverの最優先事項は、 [〜#〜] acid [〜#〜] プロパティに準拠することです。つまり、何をしても、データベースは常にトランザクションの一貫性が保たれます。

ただし、実行しようとしていることにより、一貫性のない状態になる可能性があります。 ACIDプロパティを説明するための標準的な例である銀行口座について考えてみてください。異なるファイルグループに存在する2つのアカウントがあるとします(たとえば、2つのアカウントテーブルまたは1つはパーティション化されています)。ここで、トランザクション内でファイルグループ1からファイルグループ2に送金します。次に、転送の前にファイルグループを1つに復元します。その結果、お金は現在両方のアカウントにあり、明らかに望ましい状態ではありません。

それで、あなたの例では何が起こっているのですか?

6)ファイルグループは災害前の時点に正常に復元されます。ただし、「復元中」の状態であり、アクセスできません。

8)ログの復元により、ファイルグループはデータベースの残りの部分(トランザクションレベル)で高速化されます。これを行うために、ログバックアップにキャプチャされたすべてのコミットされたトランザクションがそのファイルグループに再適用されます。ただし、削除はコミットされたトランザクションであったため、再実行されます。これにより、データベースの整合性は保たれますが、テーブルは空になります。

あなたが指しているTechnetの例は、ファイルが何らかの外部の理由でオフラインになることを前提としています。ドライブ障害。その場合、すべてのトランザクションを再適用する必要があるため、説明した復元は理にかなっています。

あなたの場合、データベースを別の場所に復元してから、データを元のテーブルにコピーして戻す必要があります。そのためには、問題のデータを含むファイルグループとプライマリファイルグループを復元するだけです。セカンダリファイルグループを復元するだけでなく、プライマリも常に復元する必要があります。これが、プライマリファイルグループにデータを含めないことが推奨される理由の1つです。そうすれば、それを復元しなければならないことによる影響も最小限に抑えられます。

1
Sebastian Meine

最後のログバックアップのすべてのトランザクションを復元したため、復元シーケンスの後にテーブルにデータがありませんでした。これには、テーブルからのデータの削除が含まれていました。

基本的に探しているのは、ポイントインタイムの復元です。これが実際の例です(:セバスチャンがすでに示唆しているように、ファイルに対してポイントインタイム復元を行うときは、PRIMARYファイルグループを復元する必要があります):

use AdventureWorks2012RestoreTest;
go

-- create a new filegroup
--
alter database AdventureWorks2012RestoreTest
add filegroup USERTABLES_01;
go

-- create a new data file in the new filegroup
--
alter database AdventureWorks2012RestoreTest
add file
(
    name = Aw2012Rt_data2,
    filename = '<backup dir>\Aw2012Rt_data2.ndf',
    size = 2 MB
) to filegroup USERTABLES_01;

-- create the duplicate table on the new filegroup
--
create table [HumanResources].[Employee_01]
(
    [BusinessEntityID] [int] NOT NULL,
    [NationalIDNumber] [nvarchar](15) NOT NULL,
    [LoginID] [nvarchar](256) NOT NULL,
    [OrganizationNode] [hierarchyid] NULL,
    [OrganizationLevel] [smallint] NULL,
    [JobTitle] [nvarchar](50) NOT NULL,
    [BirthDate] [date] NOT NULL,
    [MaritalStatus] [nchar](1) NOT NULL,
    [Gender] [nchar](1) NOT NULL,
    [HireDate] [date] NOT NULL,
    [SalariedFlag] [bit] NOT NULL,
    [VacationHours] [smallint] NOT NULL,
    [SickLeaveHours] [smallint] NOT NULL,
    [CurrentFlag] [bit] NOT NULL,
    [rowguid] [uniqueidentifier] NOT NULL,
    [ModifiedDate] [datetime] NOT NULL
) on USERTABLES_01;
go

-- populate the new table
--
insert into HumanResources.Employee_01
select *
from HumanResources.Employee;

-- get initial count of table
--
select count(*)
from HumanResources.Employee_01;
-- 290

-- initiate a full backup of the database
--
backup database AdventureWorks2012RestoreTest
to disk = '<backup dir>\Aw2012RT_full.bak'
with init;
go

-- because we need to do a point-in-time recovery we might as
-- well get the datetime stamp right before the delete
--
select getdate();
-- 2014-01-08 05:34:56.767

-- "accidentally" delete all data
--
delete from HumanResources.Employee_01;

-- verify all of the data is gone
--
select count(*)
from HumanResources.Employee_01;
-- 0

-- start the restore sequence
--
use master;
go

-- you need to restore the PRIMARY filegroup in order for point-in-time recovery
-- othewise you'll get the following error message:
-- "Point-in-time recovery is not possible unless the primary filegroup is part 
-- of the restore sequence. Omit the point-in-time clause or restore the primary filegroup."
--
backup log AdventureWorks2012RestoreTest
to disk = '<backup dir>\Aw2012RT_log.trn'
with init, norecovery;
go

restore database AdventureWorks2012RestoreTest
file = 'Aw2012Rt_data2',
filegroup = 'PRIMARY'
from disk = '\\stringermain\VmShare\temp\Aw2012RT_full.bak'
with norecovery;
go

-- now you can do point-in-time recovery with the STOPAT clause
-- specifying a datetime stamp before the delete operation
--
restore log AdventureWorks2012RestoreTest
from disk = '<backup dir>\Aw2012RT_log.trn'
with 
    stopat = '2014-01-08 05:34:56.767',
    recovery;
go

use AdventureWorks2012RestoreTest;
go

-- verify that we now have data in the table
--
select count(*)
from HumanResources.Employee_01;
-- 290

セバスチャンもその事実をほのめかしているように、削除されたデータを取り戻すことを検討している場合は、他の場所に復元してデータをコピーする方が本質的に簡単な場合があります。しかし、説明のために修正されたテストケースを示したかったのですが、howそのポイントインタイムリストアを実行します。

1
Thomas Stringer