TL;DR: Eu tenho uma corrupção não corrigida em uma exibição indexada. Aqui estão os detalhes:
Corrida
DBCC CHECKDB([DbName]) WITH EXTENDED_LOGICAL_CHECKS, DATA_PURITY, NO_INFOMSGS, ALL_ERRORMSGS
em um dos meus bancos de dados produz o seguinte erro:
Msg 8907, Nível 16, Estado 1, Linha 1 O índice espacial, índice XML ou exibição indexada 'ViewName' (objeto ID 784109934) contém linhas que não foram produzidas pela definição de exibição. Isso não representa necessariamente um problema de integridade com os dados desse banco de dados. (...)
CHECKDB encontrou 0 erros de alocação e 1 erro de consistência na tabela 'ViewName'.
repair_rebuild é o nível mínimo de reparo (...).
Entendo que esta mensagem indica que os dados materializados da exibição indexada 'ViewName' não são idênticos aos produzidos pela consulta subjacente. No entanto, a verificação manual dos dados não revela nenhuma discrepância:
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
foi usado para forçar o uso do (somente) índice em ViewName
. FORCESCAN
foi usado para impedir que a correspondência de exibição indexada aconteça. O plano de execução confirma que ambas as medidas estão funcionando.
Nenhuma linha está sendo retornada aqui, o que significa que as duas tabelas são idênticas. (Existem apenas colunas inteiras e guid, os agrupamentos não entram em jogo).
O erro não pode ser corrigido recriando o índice na exibição ou executando DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS
. Repetir as correções também não ajudou. Por que DBCC CHECKDB
relata esse erro? Como se livrar dele?
(Mesmo que a reconstrução corrigisse, minha pergunta ainda permaneceria - por que um erro é relatado, embora minhas consultas de verificação de dados sejam executadas com êxito?)
Atualização: O bug foi corrigido em algumas versões. Não consigo mais reproduzi-lo no SQL Server 2014 SP2 CU 5. O 2014 SP2 KB contém uma correção sem artigo do KB: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error
. Os dois bugs de conexão sobre isso foram fechados:
- 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
O processador de consulta pode produzir um plano de execução inválido para a consulta (correta) gerada pelo DBCC para verificar se o índice de exibição produz as mesmas linhas que a consulta de exibição subjacente.
O plano produzido pelo processador de consultas manipula incorretamente
NULLs
aImageObjectID
coluna. Raciocina incorretamente que a consultaNULLs
de visualização rejeita esta coluna, quando não o faz. Pensando queNULLs
são excluídos, ele é capaz de corresponder ao índice não clusterizado filtrado naUsers
tabela que filtra emImageObjectID IS NOT NULL
.Ao produzir um plano que usa esse índice filtrado, ele garante que as linhas com
NULL
inImageObjectID
não sejam encontradas. Essas linhas são retornadas (corretamente) do índice de exibição, portanto, parece que há uma corrupção quando não há.A definição da visualização é:
A
ON
comparação de igualdade de cláusula entreAdminUserID
eID
rejeitaNULLs
nessas colunas, mas não daImageObjectID
coluna.Parte da consulta gerada pelo DBCC é:
Este é um código genérico que compara valores de maneira
NULL
consciente. Certamente é detalhado, mas a lógica é boa.O bug no raciocínio do processador de consulta significa que um plano de consulta que usa incorretamente o índice filtrado pode ser produzido, como no fragmento de plano de exemplo abaixo:
A consulta DBCC leva um caminho de código diferente através do processador de consulta das consultas do usuário. Este caminho de código contém o bug. Quando um plano usando o índice filtrado é gerado, ele não pode ser usado com a
USE PLAN
dica para forçar esse formato de plano com o mesmo texto de consulta enviado de uma conexão de banco de dados do usuário.O caminho principal do código do otimizador (para consultas do usuário) não contém esse bug, portanto, é específico para consultas internas como as geradas pelo DBCC.
Uma investigação mais aprofundada mostra que este é um bug no DBCC CHECKDB. Um bug do Microsoft Connect foi aberto: Unfixable DBCC CHECKDB error (que também é um falso positivo e estranho) . Felizmente, consegui produzir uma reprodução para que o bug possa ser encontrado e corrigido.
O bug pode ser ocultado brincando com o esquema do banco de dados. Excluir um índice filtrado não relacionado ou remover o filtro oculta o bug. Para obter detalhes, consulte o item de conexão.
O item de conexão também contém a consulta interna que DBCC CHECKDB usa para validar o conteúdo da exibição. Ele não retorna resultados, mostrando que isso é um bug.
O bug foi corrigido em algumas versões. Não consigo mais reproduzi-lo no SQL Server 2014 SP2 CU 5.