DBCC CHECKDBの修復不可能な破損:インデックス付きビューには、ビュー定義によって生成されなかった行が含まれています


14

TL; DR:インデックス付きビューに修正不可能な破損があります。詳細は次のとおりです。


ランニング

DBCC CHECKDB([DbName]) WITH EXTENDED_LOGICAL_CHECKS, DATA_PURITY, NO_INFOMSGS, ALL_ERRORMSGS

私のデータベースのいずれかで次のエラーが生成されます:

メッセージ8907、レベル16、状態1、行1空間インデックス、XMLインデックス、またはインデックス付きビュー 'ViewName'(オブジェクトID 784109934)には、ビュー定義によって生成されなかった行が含まれています。これは、必ずしもこのデータベース内のデータの整合性の問題を表しているわけではありません。(...)

CHECKDBは、テーブル 'ViewName'で0個の割り当てエラーと1個の一貫性エラーを検出しました。

repair_rebuildは最小修復レベル(...)です。

このメッセージは、インデックス付きビュー「ViewName」の具体化されたデータが、基になるクエリが生成するものと同一ではないことを示していることを理解しています。ただし、データを手動で検証しても矛盾は発生しません。

SELECT * FROM ViewName WITH (NOEXPAND)
EXCEPT
SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...

SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...
EXCEPT
SELECT * FROM ViewName WITH (NOEXPAND)

NOEXPANDで(のみ)インデックスの使用を強制するために使用されましたViewNameFORCESCANインデックス付きビューの一致を防ぐために使用されました。実行計画により、両方の対策が機能していることが確認されます。

ここには行が返されません。つまり、2つのテーブルは同一です。(整数列とGUID列のみがあり、照合は機能しません)。

ビューでインデックスを再作成するか、を実行してもエラーを修正できませんDBCC CHECKDB REPAIR_ALLOW_DATA_LOSS。修正を繰り返しても解決しませんでした。なぜDBCC CHECKDBこのエラーを報告するのですか?それを取り除く方法は?

(再構築によって修正されたとしても、私の疑問は解決されません。データチェッククエリは正常に実行されますが、エラーが報告されるのはなぜですか?)


更新:バグはいくつかのリリースで修正されました。SQL Server 2014 SP2 CU 5では再現できなくなりました。2014SP2 KBには、KB記事なしの修正が含まれていますCreating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error。これに関する2つの接続バグがクローズされました。


1
ビューでインデックスを削除して再作成しても、DBCC CHECKDBが同じエラーを報告するということですか?ビューをドロップして最初から作成するのはどうですか?
アーロンバートランド

BOL から:インデックス付きビューでのDBCCエラーのトラブルシューティングIf the indexed view does not contain an aggregate over values of type float or real and you receive errors 8907 or 8708, drop the index on the view and re-create it. Do not use ALTER INDEX REBUILD to try to remove the differences between the stored and the computed view, because ALTER INDEX REBUILD does not recalculate the view before rebuilding the index. Then run DBCC CHECKTABLE on the View to verify no differences remain.
金武シャー

@Kinコメントを編集しました。[1]表記はコメントマークダウンでは動作しません。
アーロンバートランド

すべてを再作成しました。また、DBCC CHECKDB REPAIR_ALLOW_DATA_LOSSを実行します。ビューを再構築しましたが、同じエラーが報告されました。
usr

ビュー定義を表示できますか(ここで長すぎる場合はペーストビンで)。
アーロンバートランド

回答:


14

クエリプロセッサは、DBCCによって生成された(正しい)クエリに対して無効な実行プランを生成し、ビューインデックスが基になるビュークエリと同じ行を生成することを確認できます。

クエリプロセッサによって生成されたプランNULLsは、ImageObjectID列を誤って処理します。誤って、ビュークエリNULLsがこの列を拒否するのは、そうでない場合です。NULLs除外されていると考えると、フィルタリングするUsersテーブルのフィルタリングされた非クラスター化インデックスと一致することができますImageObjectID IS NOT NULL

このフィルター選択されたインデックスを使用するプランを作成することにより、NULLin を含む行が検出さImageObjectIDれないようにします。これらの行はビューインデックスから(正しく)返されるため、存在しない場合は破損しているように見えます。

ビューの定義は次のとおりです。

SELECT
    dbo.Universities.ID AS Universities_ID, 
    dbo.Users.ImageObjectID AS Users_ImageObjectID
FROM dbo.Universities
JOIN dbo.Users
    ON dbo.Universities.AdminUserID = dbo.Users.ID

これらの列のON句の等価比較AdminUserIDおよびID拒否NULLsは、列からではなく、拒否しImageObjectIDます。

DBCCが生成したクエリの一部は次のとおりです。

SELECT [Universities_ID], [Users_ImageObjectID], 0 as 'SOURCE'
FROM [dbo].[mv_Universities_Users_ID] tOuter WITH (NOEXPAND) 
WHERE NOT EXISTS
( 
    SELECT 1 
    FROM   [dbo].[mv_Universities_Users_ID] tInner
    WHERE 
    (
        (
            (
                [tInner].[Universities_ID] = [tOuter].[Universities_ID]
            ) 
            OR 
            (
                [tInner].[Universities_ID] IS NULL
                AND [tOuter].[Universities_ID] IS NULL
            )
        )
        AND
        (
            (
                [tInner].[Users_ImageObjectID] = [tOuter].[Users_ImageObjectID]
            ) 
            OR 
            (
                [tInner].[Users_ImageObjectID] IS NULL 
                AND [tOuter].[Users_ImageObjectID] IS NULL
            )
        )
    )
)
OPTION (EXPAND VIEWS);

これは、値をNULL意識した方法で比較する汎用コードです。確かに冗長ですが、ロジックは問題ありません。

クエリプロセッサの推論のバグは、以下のプランフラグメントの例のように、フィルタリングされたインデックスを誤って使用するクエリプランが生成される可能性があることを意味します。

誤った計画

DBCCクエリは、クエリプロセッサを介したユーザークエリとは異なるコードパスを取ります。このコードパスにはバグが含まれています。フィルター選択されたインデックスを使用するプランが生成USE PLANされるとき、ユーザーデータベース接続から送信された同じクエリテキストでそのプランの形状を強制するヒントと一緒に使用できません。

メインオプティマイザーコードパス(ユーザークエリ用)にはこのバグが含まれていないため、DBCCによって生成されるような内部クエリに固有です。


SQL Profiler Showplan XMLイベントで障害のあるプランを確認できます。これを答えとしてマークします。DBCCが通常のクエリプロセッサとは異なる方法でクエリを作成するのはなぜですか?; この回答へのリンクを接続アイテムに追加します。
usr

2
@usr DBCCは、ユーザー接続では不可能なあらゆる種類の処理を行います。こうする必要があるため、このように機能すると思いますが、Paul Randalのような人に実際の詳細を聞いてもらう必要があります。もちろん、彼は言う自由がないかもしれません。DBCC以外にも、もっと奇妙なことをするものがたくさんあることは知っています。オプティマイザーをまったく使用せずに実行計画を構築するものさえあります!
ポールホワイトモニカーを復活

6

さらに調査した結果、これはDBCC CHECKDBのバグであることがわかりました。Microsoft Connectのバグが公開されました。不可能なDBCC CHECKDBエラー(これも誤検知であり、奇妙なエラーです)。幸いなことに、バグを見つけて修正できるように再現することができました。

このバグは、データベーススキーマを操作することで隠すことができます。無関係のフィルター選択されたインデックスを削除するか、フィルターを削除すると、バグが隠されます。詳細については、接続項目を参照してください。

接続項目には、DBCC CHECKDBがビューの内容を検証するために使用する内部クエリも含まれています。結果が返されず、これがバグであることを示しています。

このバグはいくつかのリリースで修正されています。SQL Server 2014 SP2 CU 5では再現できなくなりました。


バグを再現するために、多くの(実稼働)データが必要でした(これは、計画の変更が原因である可能性があることのさらなる証拠です)。各テーブルから2列を除くすべてを削除することはできましたが、データをリリースするのは不安です。リンクした問題には、ビューの破損が必要です。ビューを再作成して、DMLによる破損が原因にならないようにしました。クエリが通常のクエリウィンドウではなくDBCC CHECKDBの下で実行されている場合、異なる計画を引き起こす可能性のあることをご存知ですか?
usr

匿名化されたデータベースがアップロードされました。すべてのインデックスを再構築してビューを再作成するスクリプトを次に示します。pastebin.com / jPEALeEw(すべてをリセットし、物理構造が正常であることを確認するのに役立ちます)。その他の役立つスクリプト:pastebin.com/KxNSwm2Jスクリプトは実行されるだけで、問題はすぐに再現するはずです。
usr

.bakのミラー:mega.co.nz/…–
usr

11.0.3349で-T272,4199,3604を使用。4199対応のクエリプロセッサの修正。そのTFを削除しました。おそらく、適切なクエリプランを誘導する必要があります。1GBのRAMを設定し、インスタンスを再起動しました(8GBでした)。これにより、NLJで見ていた2つのマージ結合の1つが変更されました。それでも再現。いくつかのプランのバリエーションを試すために、行を追加および削除しました:pastebin.com/y972Sx4dクエリの「左半結合」部分でマージ結合またはハッシュを取得すると、バグがトリガーされるようです。これを試してください:ユーザーに10万行を追加します。これにより、(並列)ハッシュ結合が確実に提供されます。
usr

DBCC CHECKDBクエリのさまざまな実行プランを含む接続アイテムに「plans.zip」をアップロードしました。大学の行数が異なると、少なくとも3つの異なる計画を作成できます。ループ結合プランでのみ問題は発生しません。マージとハッシュ結合により、バグは再現可能です。
usr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.