TL; DR: J'ai une corruption non réparable dans une vue indexée. Voici les détails:
Fonctionnement
DBCC CHECKDB([DbName]) WITH EXTENDED_LOGICAL_CHECKS, DATA_PURITY, NO_INFOMSGS, ALL_ERRORMSGS
sur l'une de mes bases de données produit l'erreur suivante:
Msg 8907, niveau 16, état 1, ligne 1 L'index spatial, l'index XML ou la vue indexée 'ViewName' (ID d'objet 784109934) contient des lignes qui n'ont pas été produites par la définition de la vue. Cela ne représente pas nécessairement un problème d'intégrité avec les données de cette base de données. (...)
CHECKDB a trouvé 0 erreur d'allocation et 1 erreur de cohérence dans la table 'ViewName'.
repair_rebuild est le niveau de réparation minimum (...).
Je comprends que ce message indique que les données matérialisées de la vue indexée 'ViewName' ne sont pas identiques à ce que la requête sous-jacente produit. Cependant, la vérification manuelle des données ne révèle aucune anomalie:
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
a été utilisé pour forcer l'utilisation de l'index (uniquement) sur ViewName
. FORCESCAN
a été utilisé pour empêcher la correspondance des vues indexées. Le plan d'exécution confirme que les deux mesures fonctionnent.
Aucune ligne n'est renvoyée ici, ce qui signifie que les deux tables sont identiques. (Il n'y a que des colonnes entières et guid, les classements n'entrent pas en jeu).
L'erreur ne peut pas être corrigée en recréant l'index sur la vue ou en exécutant DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS
. La répétition des correctifs n'a pas aidé non plus. Pourquoi DBCC CHECKDB
signale cette erreur? Comment s'en débarrasser?
(Même si la reconstruction le corrigeait, ma question resterait posée - pourquoi une erreur est-elle signalée alors que mes requêtes de vérification des données ont réussi?)
Mise à jour: le bogue a été corrigé dans certaines versions. Je ne peux plus se reproduire dans SQL Server 2014 SP2 CU 5. 2014 SP2 KB contient un correctif sans KB article: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error
. Les deux bogues de connexion à ce sujet ont été fermés:
- https://connect.microsoft.com/SQLServer/feedback/details/847233/creating-non-clustered-index-causes-dbcc-checkdb-with-extended-logical-checks-to-raise-corruption-error
- https://connect.microsoft.com/SQLServer/feedback/details/795478/unfixable-dbcc-checkdb-error-that-is-also-a-false-positive-and-otherwise-strange
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.
[1]
notation ne fonctionne pas dans la marque de commentaire.Réponses:
Le processeur de requêtes peut produire un plan d'exécution non valide pour la requête (correcte) générée par DBCC pour vérifier que l'index de vue produit les mêmes lignes que la requête de vue sous-jacente.
Le plan produit par le processeur de requêtes ne gère pas correctement
NULLs
laImageObjectID
colonne. Il raisonne à tort que la requête de vue rejetteNULLs
pour cette colonne, alors que ce n'est pas le cas. En pensant qu'ilsNULLs
sont exclus, il est capable de faire correspondre l'index non cluster filtré sur laUsers
table qui filtreImageObjectID IS NOT NULL
.En produisant un plan qui utilise cet index filtré, il garantit que les lignes avec
NULL
inImageObjectID
ne sont pas rencontrées. Ces lignes sont retournées (correctement) à partir de l'index de vue, il semble donc qu'il y ait une corruption quand il n'y en a pas.La définition de la vue est:
La
ON
comparaison d'égalité de clause entreAdminUserID
etID
rejetteNULLs
dans ces colonnes, mais pas à partir de laImageObjectID
colonne.Une partie de la requête générée par DBCC est:
Il s'agit d'un code générique qui compare les valeurs de manière
NULL
consciente. C'est certainement verbeux, mais la logique est bonne.Le bogue dans le raisonnement du processeur de requête signifie qu'un plan de requête qui utilise incorrectement l'index filtré peut être produit, comme dans l'exemple de fragment de plan ci-dessous:
La requête DBCC prend un chemin de code différent via le processeur de requêtes à partir des requêtes utilisateur. Ce chemin de code contient le bogue. Lorsqu'un plan utilisant l'index filtré est généré, il ne peut pas être utilisé avec l'
USE PLAN
indice pour forcer cette forme de plan avec le même texte de requête soumis à partir d'une connexion à la base de données utilisateur.Le chemin de code principal de l'optimiseur (pour les requêtes des utilisateurs) ne contient pas ce bogue, il est donc spécifique aux requêtes internes comme celles générées par DBCC.
la source
Une enquête plus approfondie montre qu'il s'agit d'un bogue dans DBCC CHECKDB. Un bogue Microsoft Connect a été ouvert: erreur DBCC CHECKDB non réparable (qui est également un faux positif et autrement étrange) . Heureusement, j'ai pu produire une repro afin que le bogue puisse être trouvé et corrigé.
Le bogue peut être masqué en jouant avec le schéma de base de données. La suppression d'un index filtré non lié ou la suppression du filtre masque le bogue. Pour plus de détails, veuillez consulter l'élément de connexion.
L'élément de connexion contient également la requête interne que DBCC CHECKDB utilise pour valider le contenu de la vue. Il ne renvoie aucun résultat, montrant qu'il s'agit d'un bogue.
Le bug a été corrigé dans certaines versions. Je ne peux plus le reproduire dans SQL Server 2014 SP2 CU 5.
la source