MS SQL Server 2005の破損したページ番号による破損したオブジェクトの検索

最近、MS SQL Serverデータベースの1つがSuspectに切り替わり、ログにエラーメッセージが記録されました。

メッセージ7105、レベル22、状態9、行14

データベースID 6、ページ(1:386499)、LOBデータ型ノードのスロット0は存在しません。 これは通常、データページ上のコミットされていないデータを読み取ることができるトランザクションによって発生します。 DBCC CHECKTABLEを実行します。


データベースはEmergencyに転送され、DBCC CHECKDBを実行しようとしましたが、実行はすぐに中断されました。

メッセージ8921、レベル16、状態1、行13

チェックは終了しました。 ファクトの収集中に障害が検出されました。 おそらくtempdbのスペースが不足しているか、システムテーブルに一貫性がありません。 以前のエラーを確認してください。

メッセージ7105、レベル22、状態9、行13

データベースID 6、ページ(1:386499)、LOBデータ型ノードのスロット0は存在しません。 これは通常、データページ上のコミットされていないデータを読み取ることができるトランザクションによって発生します。 DBCC CHECKTABLEを実行します。


DBCC CHECKALLOCコマンドは同様のエラーで中断されました。 SQL Serverがバージョン9.0.1399であったため、すべてが複雑でした。 RTM、更新なし。



TABLOCKヒントを使用し、トランザクション分離レベルを明示的に上げようとしても、何も起こりませんでした(tempdbで十分なディスク容量があり、WITH ESTIMATEONLYでDBCC CHECKALLOCが同じエラーで失敗しました)。 データベースが破損しているサーバーにSPをロールバックしたくはありませんでした。また、問題の特定のオブジェクトが完全に理解不能でした。 さらに、msdb.dbo.suspect_pagesには1つのレコードがありましたが、ページ番号はDBCC CHECKDBが印刷したものとは異なっていたため、DBCC CHECKDBメッセージは現実とほとんど関係がないように思われました。



DBCC CHECKDBの指示に従ってDBCC CHECKTABLEを実行するには、テーブルを知っている必要があります。 そして、長い検索の後、1つの命令が見つかりました

ご注意
エラーメッセージとコードのテーブル番号が一致しないことをおpoび申し上げます。 ログからエラーを取得し、その後、別のライブベースのテスト環境でコードを実行しました。



以下のアルゴリズムを使用して、DBCC CHECKDBおよびsuspect_pagesから両方のページのobject_idを決定しました。 問題はsuspect_pagesのページにありました



最初に行うことは、(破損したデータベースのコンテキストで) DBCC PAGE (database_id、file_id、page_id、printopt)を実行することです。



DBCC TRACEON (3604); DBCC PAGE(5, 1, 3242342, 0) DBCC TRACEOFF (3604);
      
      





どちらか:



 DBCC PAGE(5, 1, 3242342, 0) WITH TABLERESULTS.
      
      





運がよければ(またはライブベースでプレイしている場合)、結果として、Metadata:ObjectIdフィールドと、実際には目的のobject_idが表示されます。







ただし、私たちのようにあなたが幸運でない場合、以下が表示されます:

メタデータ:=オフラインDBでは使用不可
メタデータが利用できない場合、すべてが失われるわけではありません。この場合、m_objIdフィールド(AllocUnitId.idObj)が必要です。 m_objId = 255の場合、問題は、記事を閉じて何か他のものを探すことです(可能な限りすべてのスクリプトを作成し、データを削除するか、DBCC CHECKDBを "recovery"パラメーターで盲目的に実行するなど)。

スクリーンショットは、m_objId = 9931、つまり 続けることができます。



次に、割り当てユニットIDを計算するために少し計算する必要があります(割り当てユニットの詳細については、 こちらを参照してください )。

割り当てユニットID = m_objid * 65536 +(2 ^ 56)
私たちの場合:

割り当てユニットID = 9931 * 65536 +(2 ^ 56)= 72057594688765952


したがって、Allocation Unit IDを知っていると、 sys.allocation_unitsシステムビューにあるものを確認できます。



 SELECT * FROM sys.allocation_units WHERE allocation_unit_id = 72057594688765952
      
      









そして、そこに、タイプ= 1または3(IN_ROW_DATA、ROW_OVERFLOW_DATA)の場合、列container_id = sys.partitions.hobt_id(「ヒープまたはBツリーID」)、つまり リクエストを実行できます:



 SELECT * FROM sys.partitions WHERE hobt_id = 72057594661437440
      
      









そして、ここにはすでに正しいobject_idとindex_idがあります。 これで、sys.objectsとsys.indexesにあるものを確認して、実行するだけです。



 SELECT OBJECT_NAME(object_id)
      
      





幸いなことに、実際の状況とここの両方で、非クラスターインデックスが再構築された後、すべてが正常に戻ったことが確認されました(実際、いいえ、それは別の話です)。



参照

DBCC PAGEの使用方法

SQL Serverページレベルの破損のトラブルシューティングと修正

割り当て単位とは何ですか?

ページIDからテーブル名を見つける

sys.allocation_units



All Articles