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

Source: https://habr.com/ru/post/J430824/


All Articles