都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

データベースが破損したら、イヤですよねと思って、そんなことが発生してしまった時の復旧手順を簡単にまとめてみた

 データベースが破損したら、どうしましょうか? 開発エンジニアだとこのあたりは疎いですよね?なんとなく、怖くて、触れたくない所というか、なんというか。( そういう私もそんなエンジニアの一人ですwww )

 いつもの AdventureWorks データベースを使用します。テーブルを破損させ、その後復旧処理を行うので、まずデータベースをバックアップしましょう。バックアップを取得したら、Undocumented Command である、DBCC WRITEPAGE で Person.AddressType テーブルを破損させます。まずは、テーブルのどの個所を破損させるか決定するために、下記のコマンドでテーブルのページ構造を参照してみましょう。( ここのページを参考にしました。 データベースの復旧モデルは完全にしておいてください。そうでないと、ページの復元ができません。) 

DBCC IND (N'AdventureWorks2012', N'Person.AddressType', -1);

f:id:koogucc11:20140420114337p:plain

 後でページ復元を行うため、データベースのバックアップを取得しておきます。

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);

f:id:koogucc11:20140419190255p:plain

 シングルユーザーモードからマルチユーザーモードに変更します。

ALTER DATABASE AdventureWorks2012 SET MULTI_USER

 テーブルが破損しているか確認してみましょう。SQL 文を発行するとエラーが発生します。DBCC WRITEPAGE で破壊した個所がメッセージに表示されているのがわかります。( 下図の赤線部分です。 )

USE AdventureWorks2012
SELECT * FROM Person.AddressType

f:id:koogucc11:20140419191606p:plain

 上記の現象発生後、suspect_pages を使用することで検出できます。( suspect_pages に関して、詳しくはここを参照してください。)

SELECT * FROM msdb..suspect_pages

f:id:koogucc11:20140420110745p:plain

 破損したページをバックアップから戻すには、下記の 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

f:id:koogucc11:20140420212050p:plain

 修復したテーブルにアクセスします。テーブルが修復され、正常にアクセス可能になりました。

USE AdventureWorks2012
SELECT * FROM Person.AddressType;

f:id:koogucc11:20140420212344p:plain     

 今回の一連の手順に関しては、まず SQL Server のデータ管理の仕組みを知っておいたほうがより理解 (そうでないとダメ?) ができると思います。色々な方が SQL Server の概念について説明されているので、ググって... じゃなくて、ビングって (笑) ください。( いつか、自分流に説明してみようかな... ) 

※このあたりを詳しくなるためには、DBCC IND のほかに、DCC PAGE あたりにも詳しくなる必要がありますね。このあたりも勉強する必要がありますね。

DBCC TRACEON(3604, -1)
DBCC PAGE('AdventureWorks2012', 1, 843, 3) WITH TABLERESULTS
DBCC TRACEOFF(3604, -1)

f:id:koogucc11:20140420220825p:plain