DBCC CHECKDB corrupción no reparable: la vista indizada contiene filas que no fueron producidas por la definición de vista


14

TL; DR: Tengo una corrupción no reparable en una vista indizada. Aquí están los detalles:


Corriendo

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

en una de mis bases de datos produce el siguiente error:

Mensaje 8907, Nivel 16, Estado 1, Línea 1 El índice espacial, el índice XML o la vista indizada 'ViewName' (ID de objeto 784109934) contiene filas que no fueron producidas por la definición de la vista. Esto no representa necesariamente un problema de integridad con los datos en esta base de datos. (...)

CHECKDB encontró 0 errores de asignación y 1 errores de coherencia en la tabla 'ViewName'.

repair_rebuild es el nivel mínimo de reparación (...).

Entiendo que este mensaje indica que los datos materializados de la vista indexada 'ViewName' no son idénticos a los que produce la consulta subyacente. Sin embargo, la verificación manual de los datos no genera ninguna discrepancia:

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)

NOEXPANDse usó para forzar el uso del (único) índice en ViewName. FORCESCANse usó para evitar que ocurriera coincidencia de vista indexada. El plan de ejecución confirma que ambas medidas están funcionando.

Aquí no se devuelven filas, lo que significa que las dos tablas son idénticas. (Solo hay columnas enteras y guid, las colaciones no entran en juego).

El error no se puede solucionar recreando el índice en la vista o ejecutando DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS. Repetir las correcciones tampoco ayudó. ¿Por qué DBCC CHECKDBinforma este error? Cómo deshacerse de él?

(Incluso si la reconstrucción lo solucionaba, mi pregunta seguiría en pie: ¿por qué se informa un error aunque mis consultas de verificación de datos se ejecutan correctamente?)


Actualización: el error se ha solucionado en algunas versiones. Ya no puedo reproducirlo en SQL Server 2014 SP2 CU 5. El SP2 KB 2014 contiene una corrección sin artículo de KB: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error. Los dos errores de conexión sobre esto se han cerrado:


1
¿Está diciendo que descartó y volvió a crear el índice en la vista y DBCC CHECKDB aún informa el mismo error? ¿Qué pasa con soltar la vista y crearla desde cero?
Aaron Bertrand

De BOL: Solución de problemas de errores DBCC en vistas indexadas 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 Edité tu comentario. La [1]notación no funciona en el marcado de comentarios.
Aaron Bertrand

Yo recreé todo. También dejé correr DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS. Dijo que reconstruyó la vista, pero luego informó el mismo error.
usr

¿Puedes mostrar la definición de la vista (si es demasiado larga aquí, entonces en un pastebin)?
Aaron Bertrand

Respuestas:


14

El procesador de consultas puede generar un plan de ejecución no válido para la consulta (correcta) generada por DBCC para verificar que el índice de vista produce las mismas filas que la consulta de vista subyacente.

El plan producido por el procesador de consultas maneja incorrectamente NULLsla ImageObjectIDcolumna. Motiva incorrectamente que la consulta de vista rechaza NULLsesta columna, cuando no lo hace. Pensando que NULLsestán excluidos, puede hacer coincidir el índice filtrado no agrupado en la Userstabla que se filtra ImageObjectID IS NOT NULL.

Al producir un plan que utiliza este índice filtrado, asegura que no se encuentren filas con NULLin ImageObjectID. Estas filas se devuelven (correctamente) desde el índice de vista, por lo que parece que hay una corrupción cuando no la hay.

La definición de la vista es:

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

La ONcláusula de comparación de igualdad entre AdminUserIDy IDrechaza NULLsen esas columnas, pero no de la ImageObjectIDcolumna.

Parte de la consulta generada por DBCC es:

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

Este es un código genérico que compara valores de manera NULLconsciente. Ciertamente es detallado, pero la lógica está bien.

El error en el razonamiento del procesador de consultas significa que se puede generar un plan de consulta que usa incorrectamente el índice filtrado, como en el fragmento de plan de ejemplo a continuación:

Plan erróneo

La consulta DBCC toma una ruta de código diferente a través del procesador de consultas de las consultas de los usuarios. Esta ruta de código contiene el error. Cuando se genera un plan que usa el índice filtrado, no se puede usar con la USE PLANsugerencia para forzar esa forma de plan con el mismo texto de consulta enviado desde una conexión de base de datos de usuario.

La ruta del código del optimizador principal (para consultas de usuarios) no contiene este error, por lo que es específica para consultas internas como las generadas por DBCC.


Puedo ver el plan defectuoso en el evento XML Profiler Showplan XML. Marcaré esto como la respuesta .; ¿Por qué DBCC crea la consulta de una manera diferente que el procesador de consultas normal ?; Agregaré un enlace a esta respuesta al elemento de conexión.
usr

2
@usr DBCC hace todo tipo de cosas que no serían posibles desde una conexión de usuario. Me imagino que funciona de esta manera porque tiene que hacerlo, pero tendrías que pedirle a alguien como Paul Randal que obtenga los detalles reales sobre eso. Puede que no tenga la libertad de decirlo, por supuesto. Sé que hay muchas cosas fuera de DBCC que hacen cosas aún más extrañas; ¡algunos incluso construyen un plan de ejecución sin pasar por el optimizador!
Paul White 9

6

La investigación adicional muestra que este es un error en DBCC CHECKDB. Se ha abierto un error de Microsoft Connect: error de DBCC CHECKDB no reparable (que también es un falso positivo y de otro modo extraño) . Afortunadamente, pude producir una reproducción para que el error pueda ser encontrado y reparado.

El error puede ocultarse jugando con el esquema de la base de datos. Eliminar un índice filtrado no relacionado o eliminar el filtro oculta el error. Para más detalles, consulte el elemento de conexión.

El elemento de conexión también contiene la consulta interna que DBCC CHECKDB usa para validar el contenido de la vista. No devuelve resultados, lo que demuestra que se trata de un error.

El error se ha solucionado en algunas versiones. Ya no puedo reproducirlo en SQL Server 2014 SP2 CU 5.


Se necesitaban muchos datos (de producción) para reproducir el error (lo que es una prueba más de que un cambio de plan podría ser la causa). No me siento cómodo lanzando los datos, aunque pude eliminar todas las columnas excepto dos de cada tabla. El problema al que se vinculó requiere causar una corrupción en la vista. Volví a crear la vista para que la causa no sea la corrupción debido a DML .; ¿Sabe algo que pueda causar un plan diferente si la consulta se ejecuta bajo DBCC CHECKDB en lugar de en una ventana de consulta normal?
usr

Se acaba de subir una base de datos anónima. Aquí hay un script que reconstruye todos los índices y recrea la vista: pastebin.com/jPEALeEw (útil para restablecer todo y asegurarse de que la estructura física esté bien). Otros scripts útiles: pastebin.com/KxNSwm2J Los scripts deberían ejecutarse y el problema debería reprobarse de inmediato.
usr

Mirror of the .bak: mega.co.nz/…
usr

El 11.0.3349 con -T272,4199,3604. 4199 correcciones de procesador de consultas habilitadas. Acabo de quitar ese TF .; Tal vez necesitamos inducir el plan de consulta correcto. Ahora configuré 1 GB de RAM y reinicié la instancia (era de 8 GB). Eso cambió una de las dos uniones de fusión que estaba viendo a NLJ. Todavía repros .; Para probar algunas variaciones del plan, agregué y eliminé filas: pastebin.com/y972Sx4d El error parece desencadenarse si obtengo una combinación de fusión o un hash en la parte "izquierda anti semi unión" de la consulta. Pruebe esto: agregue 100k filas a los usuarios. Esto me da de manera confiable un hash (paralelo) para mí.
usr

Acabo de subir "planes.zip" al elemento de conexión que contiene diferentes planes de ejecución para la consulta DBCC CHECKDB. Con diferentes recuentos de filas en las universidades, puedo producir al menos tres planes diferentes. Solo con el plan de uniones de bucle no se produce el problema. Con las combinaciones merge y hash, el error es reproducible.
Usr
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.