Nicht korrigierbare Beschädigung von DBCC CHECKDB: Die indizierte Sicht enthält Zeilen, die nicht von der Sichtdefinition erstellt wurden

14

TL; DR: Ich habe eine unfixierbare Beschädigung in einer indizierten Ansicht. Hier sind die Details:


Laufen

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

In einer meiner Datenbanken tritt der folgende Fehler auf:

Meldung 8907, Ebene 16, Status 1, Zeile 1 Der räumliche Index, der XML-Index oder die indizierte Sicht 'ViewName' (Objekt-ID 784109934) enthält Zeilen, die nicht von der Sichtdefinition erstellt wurden. Dies ist nicht unbedingt ein Integritätsproblem mit den Daten in dieser Datenbank. (...)

CHECKDB hat in der Tabelle 'ViewName' 0 Zuordnungsfehler und 1 Konsistenzfehler gefunden.

repair_rebuild ist die Mindestreparaturstufe (...).

Ich verstehe, dass diese Nachricht darauf hinweist, dass die materialisierten Daten der indizierten Ansicht 'ViewName' nicht mit den Ergebnissen der zugrunde liegenden Abfrage identisch sind. Die manuelle Überprüfung der Daten führt jedoch nicht zu Unstimmigkeiten:

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)

NOEXPANDwurde verwendet, um die Verwendung des (einzigen) Index zu erzwingen ViewName. FORCESCANwurde verwendet, um den Abgleich der indizierten Ansicht zu verhindern. Der Ausführungsplan bestätigt, dass beide Maßnahmen wirksam sind.

Hier werden keine Zeilen zurückgegeben, was bedeutet, dass die beiden Tabellen identisch sind. (Es gibt nur Ganzzahl- und Guid-Spalten, Kollatierungen kommen nicht ins Spiel).

Der Fehler kann nicht behoben werden, indem der Index für die Ansicht neu erstellt oder ausgeführt wird DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS. Das Wiederholen der Fixes hat auch nicht geholfen. Warum wird DBCC CHECKDBdieser Fehler gemeldet? Wie kann man es loswerden?

(Selbst wenn das Problem durch Neuerstellung behoben wird, bleibt meine Frage bestehen. Warum wird ein Fehler gemeldet, obwohl meine Abfragen zur Datenüberprüfung erfolgreich ausgeführt wurden?)


Update: Der Fehler wurde in einigen Releases behoben. Ich kann nicht reproduzieren länger in SQL Server 2014 SP2 CU 5. 2014 SP2 KB ein Update ohne KB - Artikel enthält: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error. Die beiden Verbindungsfehler wurden geschlossen:

usr
quelle
1
Wollen Sie damit sagen, dass Sie den Index für die Sicht gelöscht und neu erstellt haben und DBCC CHECKDB weiterhin denselben Fehler meldet? Wie wäre es, die Ansicht zu löschen und von Grund auf neu zu erstellen?
Aaron Bertrand
Von BOL: Problembehandlung bei DBCC-Fehlern in indizierten Ansichten 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 Shah
@Kin Ich habe deinen Kommentar bearbeitet. Die [1]Notation funktioniert nicht im Kommentar-Mark-Down.
Aaron Bertrand
Ich habe alles nachgebaut. Ich habe auch DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS ausgeführt. Es wurde gesagt, dass die Ansicht neu erstellt wurde, aber dann wurde der gleiche Fehler gemeldet.
USR
Können Sie die Ansichtsdefinition anzeigen (wenn zu lang, dann in einem Pastebin)?
Aaron Bertrand

Antworten:

14

Der Abfrageprozessor kann einen ungültigen Ausführungsplan für die von DBCC generierte (richtige) Abfrage erstellen, um zu überprüfen, ob der Ansichtsindex dieselben Zeilen wie die zugrunde liegende Ansichtsabfrage erzeugt.

Der vom Abfrageprozessor erstellte Plan wird NULLsfür die ImageObjectIDSpalte falsch verarbeitet . NULLsWenn dies nicht der Fall ist , wird die Ansichtsabfrage fälschlicherweise für diese Spalte abgelehnt. Zu denken , dass NULLsausgeschlossen werden, ist es in der Lage das gefilterte nicht gruppierten Index auf dem übereinstimmen UsersTabelle auf die Filter ImageObjectID IS NOT NULL.

Indem ein Plan erstellt wird, der diesen gefilterten Index verwendet, wird sichergestellt, dass keine Zeilen mit NULLin gefunden ImageObjectIDwerden. Diese Zeilen werden (korrekt) aus dem Ansichtsindex zurückgegeben. Es scheint also, dass eine Beschädigung vorliegt, wenn dies nicht der Fall ist.

Die Ansichtsdefinition lautet:

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

Der ONVergleich der Klauselgleichheit zwischen AdminUserIDund IDlehnt NULLsin diesen Spalten ab, jedoch nicht in der ImageObjectIDSpalte.

Ein Teil der von DBCC generierten Abfrage ist:

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

Dies ist ein generischer Code, der Werte NULLbewusst vergleicht . Es ist sicherlich ausführlich, aber die Logik ist in Ordnung.

Der Fehler in der Argumentation des Abfrageprozessors bedeutet, dass möglicherweise ein Abfrageplan erstellt wird, der den gefilterten Index falsch verwendet, wie im folgenden Beispielplanfragment:

Falscher Plan

Die DBCC-Abfrage verwendet einen anderen Codepfad durch den Abfrageprozessor als Benutzerabfragen. Dieser Codepfad enthält den Fehler. Wenn ein Plan mit dem gefilterten Index generiert wird, kann er nicht mit dem USE PLANHinweis verwendet werden, um diese Planform mit demselben Abfragetext zu erzwingen, der von einer Benutzerdatenbankverbindung gesendet wurde.

Der Haupt-Optimierer-Codepfad (für Benutzerabfragen) enthält diesen Fehler nicht, so dass er für interne Abfragen wie die von DBCC generierten spezifisch ist.

Paul White Monica wieder einsetzen
quelle
Ich kann den fehlerhaften Plan im SQL Profiler Showplan XML-Ereignis sehen. Ich werde dies als Antwort markieren .; Warum erstellt DBCC die Abfrage anders als der normale Abfrageprozessor ?; Ich werde einen Link zu dieser Antwort zum Verbindungselement hinzufügen.
USR
2
@usr DBCC führt alle möglichen Aktionen aus, die mit einer Benutzerverbindung nicht möglich wären. Ich stelle mir vor, es funktioniert so, weil es so sein muss, aber Sie müssten jemanden wie Paul Randal bitten, die wahren Einzelheiten darüber zu erfahren. Er könnte natürlich nicht frei sein zu sagen. Ich weiß, dass es viele Dinge außerhalb von DBCC gibt, die noch seltsamer sind. Einige erstellen sogar einen Ausführungsplan, ohne den Optimierer zu durchlaufen!
Paul White Reinstate Monica
6

Weitere Untersuchungen haben ergeben, dass dies ein Fehler in DBCC CHECKDB ist. Ein Microsoft Connect-Fehler wurde geöffnet: Unfixable DBCC CHECKDB error (das ist auch falsch positiv und ansonsten seltsam) . Zum Glück konnte ich einen Repro produzieren, damit der Fehler gefunden und behoben werden kann.

Der Fehler kann durch Spielen mit dem Datenbankschema ausgeblendet werden. Durch Löschen eines nicht verknüpften gefilterten Index oder Entfernen des Filters wird der Fehler ausgeblendet. Einzelheiten entnehmen Sie bitte dem Verbindungselement.

Das Verbindungselement enthält auch die interne Abfrage, mit der DBCC CHECKDB den Inhalt der Ansicht überprüft. Es werden keine Ergebnisse zurückgegeben, was darauf hinweist, dass dies ein Fehler ist.

Der Fehler wurde in einigen Releases behoben. Ich kann es in SQL Server 2014 SP2 CU 5 nicht mehr reproduzieren.

usr
quelle
Es wurden viele (Produktions-) Daten benötigt, um den Fehler zu reproduzieren (was ein weiterer Beweis dafür ist, dass eine Planänderung die Ursache sein könnte). Es ist mir unangenehm, die Daten freizugeben, obwohl ich alle bis auf zwei Spalten aus jeder Tabelle löschen konnte. Das Problem, mit dem Sie verknüpft haben, verursacht möglicherweise eine Beschädigung in der Ansicht. Ich habe die Ansicht neu erstellt, damit keine Beschädigung aufgrund von DML die Ursache sein kann .; Kennen Sie irgendetwas, das einen anderen Plan verursachen könnte, wenn die Abfrage unter DBCC CHECKDB anstatt in einem normalen Abfragefenster ausgeführt wird?
USR
Eine anonymisierte Datenbank wurde gerade hochgeladen. Hier ist ein Skript, das alle Indizes neu erstellt und die Ansicht neu erstellt: pastebin.com/jPEALeEw (nützlich, um alles zurückzusetzen und sicherzustellen, dass die physische Struktur in Ordnung ist). Andere hilfreiche Skripte: pastebin.com/KxNSwm2J Die Skripte sollten nur ausgeführt werden und das Problem sollte sofort behoben werden.
USR
Spiegel der .bak: mega.co.nz/…
usr
Am 11.0.3349 mit -T272,4199,3604. Korrekturen für 4199 aktivierte Abfrageprozessoren. Ich habe gerade das TF entfernt .; Vielleicht müssen wir den richtigen Abfrageplan einführen. Ich habe jetzt 1GB RAM eingestellt und die Instanz neu gestartet (war 8GB). Das änderte einen der beiden Merge-Joins, die ich für NLJ sah. Noch Repro .; Um einige Planvarianten auszuprobieren, habe ich Zeilen hinzugefügt und entfernt: pastebin.com/y972Sx4d Der Fehler scheint auszulösen, wenn ich eine Zusammenführung oder einen Hash im Teil "Linke Antisemitverknüpfung" der Abfrage erhalte. Versuchen Sie Folgendes: Fügen Sie Benutzern 100.000 Zeilen hinzu. Dies gibt mir zuverlässig einen (parallelen) Hash-Join.
USR
Ich habe gerade "plans.zip" in das Verbindungselement hochgeladen, das verschiedene Ausführungspläne für die DBCC CHECKDB-Abfrage enthält. Mit unterschiedlichen Reihenzahlen an Universitäten kann ich mindestens drei verschiedene Pläne erstellen. Nur mit dem Loop Joins Plan tritt das Problem nicht auf. Mit Merge und Hash Joins ist der Fehler reproduzierbar.
usr