バックアップ戻すことってほとんどないですよね。

幸か不幸か運用環境でマジでリストアしたことって一度もありません。

操作を忘れがちなので実験してみます。

環境はSQL Server 2012 express.

実験用データベース

Database名「backuptest」を完全復旧モデルで作成します。

テーブル

1
2
3
4
CREATE TABLE TEST_TAB(
	id int identity,
	COMMENT nvarchar(255)
)

更新とバックアップ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
INSERT INTO TEST_TAB(COMMENT) VALUES ('バックアップ前にインサート')
go
backup database backuptest to disk='C:\TEMP\backuptest_1.bak'
go
INSERT INTO TEST_TAB(COMMENT) VALUES ('バックアップ1後にインサート')
go
backup log backuptest  to disk='C:\TEMP\backuptest_1.trn'
go
INSERT INTO TEST_TAB(COMMENT) VALUES ('Transactio log バックアップ1後にインサート')
go
backup log backuptest  to disk='C:\TEMP\backuptest_2.trn'
go
INSERT INTO TEST_TAB(COMMENT) VALUES ('Transactio log バックアップ2後にインサート')	--こいつは戻ってこない?

データの内容的にはこんな感じになります。

1
2
3
4
5
6
7
select * from TEST_TAB
id          COMMENT
----------- -----------------------------------------
1           バックアップ前にインサート
2           バックアップ1後にインサート
3           Transactio log バックアップ1後にインサート
4           Transactio log バックアップ2後にインサート

戻したくなる操作をしてみる(やらかす)

まれによくあるミスをしたとします。

1
2
select getdate()
update TEST_TAB set COMMENT='where無しで更新してしまいました'

今まで積み上げてきた大事なデータがきれいに上書きされてしまっております。

1
2
3
4
5
6
7
select * from TEST_TAB
id          COMMENT
----------- -----------------------------
1           where無しで更新してしまいました
2           where無しで更新してしまいました
3           where無しで更新してしまいました
4           where無しで更新してしまいました

ちなみにやらかした時刻は”2018-11-29 11:00:15.673″. この時刻、すごく大事なので、やばいと思ったら時刻をメモっときましょう

リカバリしてみる

リカバリの際はいきなりリストアしないで、まずは最後のトランザクションのバックアップを取ります。同時にリカバリモードに移行します。

1
2
USE [master]
backup log backuptest  to disk='C:\TEMP\backuptest_recovery.trn' WITH NORECOVERY

NORECOVERYをつけると(Restoring)となって、DBが使えなくなります。

リストア

最後のトランザクションログバックアップの一個前まで順にリストアします。

この時WITH NORECOVERYを必ずつけます。そうしとかないとSQLServerがリカバリ終わったと思って、DBを通常の状態(運用状態)に戻してしまい、追加のRESTORができなくなるうえに、新たなトランザクションも発生したりして収拾がつかなくなります。

1
2
3
RESTORE DATABASE [backuptest] FROM  DISK = N'C:\TEMP\backuptest_1.bak' WITH NORECOVERY, REPLACE
RESTORE LOG [backuptest] FROM  DISK = N'C:\TEMP\backuptest_1.trn'  WITH NORECOVERY
RESTORE LOG [backuptest] FROM  DISK = N'C:\TEMP\backuptest_2.trn'  WITH NORECOVERY

最後のトランザクションログバックアップをRESTOREするときに、STOPATに「やらかしたちょっと前の日時」を設定して、やらかす直前の状態に戻します。

1
RESTORE LOG [backuptest] FROM  DISK = N'C:\TEMP\backuptest_recovery.trn'  WITH NORECOVERY , STOPAT='2018-11-29 11:00:10.673'

最後にDBを通常の状態(運用状態)に戻します。

1
RESTORE DATABASE [backuptest] WITH RECOVERY

無事id:4のも含めて全部戻ってきました。

1
2
3
4
5
6
7
select * from TEST_TAB
id          COMMENT
----------- ----------------------------------------
1           バックアップ前にインサート
2           バックアップ1後にインサート
3           Transactio log バックアップ1後にインサート
4           Transactio log バックアップ2後にインサート

要点

  • リストア前にTransaction Logバックアップ
  • NORECOVERY超大事
  • やらかした時刻をメモれ

とはいえ

この方法は普段から定期的にバックアップを取ってないと使えません。

まぁ、データベース運用しててバックアップ無してことは無いと思いますが。

運用状態で普通に更新されているDBなんかだと、STOPATでは対応しきれないと思います。

別のDB名でリストアして、手動でリカバリとか別の方法が必要かな。

時刻をメモるのも無理があるので、テーブルには自動でUpdate日時を記録するようにしときたいところ。