データベースが破損したら、どうしましょうか? 開発エンジニアだとこのあたりは疎いですよね?なんとなく、怖くて、触れたくない所というか、なんというか。( そういう私もそんなエンジニアの一人ですwww )
いつもの AdventureWorks データベースを使用します。テーブルを破損させ、その後復旧処理を行うので、まずデータベースをバックアップしましょう。バックアップを取得したら、Undocumented Command である、DBCC WRITEPAGE で Person.AddressType テーブルを破損させます。まずは、テーブルのどの個所を破損させるか決定するために、下記のコマンドでテーブルのページ構造を参照してみましょう。( ここのページを参考にしました。 データベースの復旧モデルは完全にしておいてください。そうでないと、ページの復元ができません。)
DBCC IND (N'AdventureWorks2012', N'Person.AddressType', -1);
後でページ復元を行うため、データベースのバックアップを取得しておきます。
BACKUP DATABASE [AdventureWorks2012] TO DISK = N'C:\Data\Backup\AdventureWorks.bak' WITH NOFORMAT, NOINIT, NAME = N'AdventureWorks2012FullDatabaseBackup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
PageFID = 1, PagePID = 843 の部分を破損させてみましょう。DBCC WRITEPAGE はシングルユーザーモードでしか動作しないので、マルチユーザーモードからシングルユーザーモードにしておきます。
ALTER DATABASE AdventureWorks2012 SET SINGLE_USER
DBCC WRITEPAGE ('AdventureWorks2012', 1, 843, 4000, 1, 0x45, 1);
シングルユーザーモードからマルチユーザーモードに変更します。
ALTER DATABASE AdventureWorks2012 SET MULTI_USER
テーブルが破損しているか確認してみましょう。SQL 文を発行するとエラーが発生します。DBCC WRITEPAGE で破壊した個所がメッセージに表示されているのがわかります。( 下図の赤線部分です。 )
USE AdventureWorks2012
SELECT * FROM Person.AddressType
上記の現象発生後、suspect_pages を使用することで検出できます。( suspect_pages に関して、詳しくはここを参照してください。)
SELECT * FROM msdb..suspect_pages
破損したページをバックアップから戻すには、下記の DDL 文を実行します。
USE master
RESTORE DATABASE AdventureWorks2012 PAGE='1:843' FROM DISK = N'C:\Data\Backup\AdventureWorks.bak'
WITH FILE = 1, NORECOVERY, NOUNLOAD, STATS = 5
BACKUP LOG AdventureWorks2012 TO DISK = N'C\Data\AdventureWorksLogBackup.bak'
WITH NOFORMAT, NOINIT, NAME = N'AdventureWorksLogBackup',NOSKIP, NOREWIND, NOUNLOAD, STATS = 5
RESTORE LOG AdventureWorks2012 FROM DISK = N'C:\Data\AdventureWorksLogBackup.bak'
WITH NOUNLOAD, STATS = 5
修復したテーブルにアクセスします。テーブルが修復され、正常にアクセス可能になりました。
USE AdventureWorks2012
SELECT * FROM Person.AddressType;
今回の一連の手順に関しては、まず SQL Server のデータ管理の仕組みを知っておいたほうがより理解 (そうでないとダメ?) ができると思います。色々な方が SQL Server の概念について説明されているので、ググって... じゃなくて、ビングって (笑) ください。( いつか、自分流に説明してみようかな... )
※このあたりを詳しくなるためには、DBCC IND のほかに、DCC PAGE あたりにも詳しくなる必要がありますね。このあたりも勉強する必要がありますね。
DBCC TRACEON(3604, -1)
DBCC PAGE('AdventureWorks2012', 1, 843, 3) WITH TABLERESULTS
DBCC TRACEOFF(3604, -1)