Database
 sql >> Base de Dados >  >> RDS >> Database

A trava DBCC_OBJECT_METADATA


Continuando minha série de artigos sobre travas, desta vez vou discutir a trava DBCC_OBJECT_METADATA e mostrar como ela pode ser um grande gargalo para verificações de consistência anteriores ao SQL Server 2016 em determinadas circunstâncias. O problema afeta DBCC CHECKDB, DBCC CHECKTABLE e DBCC CHECKFILEGROUP, mas, para maior clareza, farei referência apenas a DBCC CHECKDB no restante deste post.

Você pode se perguntar por que estou escrevendo sobre um problema que afeta versões mais antigas, mas ainda há um grande número de instâncias do SQL Server 2014 e mais antigas, por isso é um tópico válido para minha série.

Eu recomendo fortemente que você leia o post inicial da série antes deste, para que você tenha todo o conhecimento geral sobre travas.

O que é a trava DBCC_OBJECT_METADATA?


Para explicar essa trava, preciso explicar um pouco sobre como funciona o DBCC CHECKDB.

Entre o grande número de verificações de consistência que DBCC CHECKDB executa está uma verificação da exatidão de índices não clusterizados. Especificamente, o DBCC CHECKDB garante:
  1. Para cada registro de índice não clusterizado em cada índice não clusterizado, há exatamente um registro de dados "correspondente" na tabela base (um heap ou um índice clusterizado)
  2. Para cada registro de dados em uma tabela, há exatamente um registro de índice não clusterizado "correspondente" em cada índice não clusterizado definido para a tabela, levando em consideração os índices filtrados

Sem se aprofundar muito nos detalhes de como isso é feito, para cada registro de dados em uma tabela, DBCC CHECKDB constrói cada registro de índice não clusterizado que deve existir para cada índice não clusterizado e garante que o registro de índice não clusterizado corresponda exatamente ao real. registro de índice não clusterizado. Se o índice não clusterizado tiver uma coluna computada nele (como parte da chave de índice não clusterizado ou como uma coluna INCLUDEd), DBCC CHECKDB precisará descobrir o valor da coluna computada a ser usado ao construir os registros de índice.

Assim como as verificações de correção do índice não clusterizado, se houver um erro persistente computada na definição de uma tabela, para cada registro de dados na tabela, DBCC CHECKDB deve verificar se o valor persistido está correto, independentemente de essa coluna fazer parte de um índice não clusterizado ou não.

Então, como ele descobre os valores calculados da coluna?

O Query Processor fornece um mecanismo para calcular valores de colunas computados, chamado de "avaliador de expressão". DBCC CHECKDB chama essa função, fornecendo informações de metadados apropriadas e o registro de dados, e o avaliador de expressão usa a definição armazenada da coluna computada nos metadados e os valores do registro de dados e retorna o valor da coluna computada para DBCC CHECKDB usar . O funcionamento interno do avaliador de expressão está fora do controle do código DBCC, mas para poder usar o avaliador de expressão, um latch deve ser adquirido primeiro; a trava DBCC_OBJECT_METADATA.

Como a trava se torna um gargalo?


Aqui está o problema:há apenas um modo aceitável no qual o latch DBCC_OBJECT_METADATA pode ser adquirido antes de usar o avaliador de expressão, e esse é o modo EX (exclusivo). E como você saberá lendo o post de introdução da série, apenas um thread por vez pode segurar a trava no modo EX.

Reunindo todas essas informações:quando um banco de dados tem colunas computadas persistentes ou índices não clusterizados que possuem colunas computadas neles, o avaliador de expressão deve ser usado. Se a edição do SQL Server for Enterprise, o DBCC CHECKDB poderá usar paralelismo e, portanto, terá vários threads executando as várias verificações. E assim que você tiver vários threads tentando adquirir uma trava no modo EX, essa trava se tornará um gargalo. O tamanho do gargalo depende de quanto o avaliador de expressão precisa ser usado, portanto, quanto mais colunas computadas persistentes ou índices não clusterizados usando colunas computadas houver, e quanto maior o número de linhas de tabela nessas tabelas, quanto maior o gargalo, a trava DBCC _OBJECT_METADATA se torna.

Mas lembre-se, esse gargalo só acontece para versões do SQL Server anteriores ao SQL Server 2016. No SQL Server 2016 a Microsoft decidiu "corrigir" o gargalo desativando as verificações de índices não clusterizados usando colunas computadas por padrão e fazendo-as apenas quando o WITH A opção EXTENDED_LOGICAL_CHECKS é usada.

Mostrando o gargalo


Você pode reproduzir facilmente o gargalo executando DBCC CHECKDB em um banco de dados que tenha colunas computadas persistentes ou índices não clusterizados com colunas computadas, e o banco de dados AdventureWorks fornecido pela Microsoft é um ótimo exemplo. Você pode baixar backups do AdventureWorks para sua versão do SQL Server aqui. Executei alguns testes usando um banco de dados AdventureWorks2014 em uma instância do SQL Server 2014 (em um Dell R720 de 32 núcleos) e ampliei o banco de dados para algumas centenas de GB usando os scripts de Jonathan.

Quando executei o DBCC CHECKDB, com o servidor MAXDOP definido como 0, demorou mais de 5 horas para ser executado. O tipo de espera LATCH_EX foi responsável por cerca de 30% das esperas, com cada espera sendo apenas 1 milissegundo, e 99% das esperas LATCH_EX foram para a trava DBCC_OBJECT_METADATA.

Procurei índices não clusterizados contendo colunas computadas usando o seguinte código:
SELECT [s].[name] AS [Schema], [o].[name] AS [Object], [i].[name] AS [Index], [c].[name] AS [Column ], [ic].* FROM sys.columns [c] JOIN sys.index_columns [ic] ON [ic].[object_id] =[c].[object_id] AND [ic].[column_id] =[c]. [column_id] JOIN sys.indexes [i] ON [i].[object_id] =[ic].[object_id] AND [i].[index_id] =[ic].[index_id] JOIN sys.objects [o] ON [i].[object_id] =[o].[object_id] JOIN sys.schemas [s] ON [o].[schema_id] =[s].[schema_id] WHERE [c].[is_computed] =1; 
Esse código encontrou seis índices não clusterizados no banco de dados AdventureWorks2014. Desativei todos os seis índices (usando ALTER INDEX … DISABLE) e executei novamente o DBCC CHECKDB e ele foi concluído em cerca de 18 minutos. Portanto, o gargalo da trava DBCC_OBJECT_METADATA foi um fator importante para fazer com que o DBCC CHECKDB fosse executado mais de 16 vezes mais lento!

Resumo


Infelizmente, desabilitar índices não clusterizados usando colunas computadas (e depois reativá-los usando ALTER INDEX … REBUILD) é a *única* maneira de remover o gargalo de trava DBCC_OBJECT_METADATA em versões anteriores ao SQL Server 2016, mantendo todas as outras funcionalidades do DBCC CHECKDB. Desabilitar índices não clusterizados provavelmente não é algo que você desejará fazer em um ambiente de produção, a menos que tenha uma janela de manutenção de atividade zero. Isso significa que você provavelmente só desativará esses índices não clusterizados para remover o gargalo se suas verificações de consistência forem descarregadas em outro servidor usando o método backup-copy-restore-CHECKDB.

Outra maneira de fazer isso é usar a opção WITH PHYSICAL_ONLY ao executar DBCC CHECKDB, mas você perde todas as verificações lógicas detalhadas, então não sou um grande fã de recomendar isso como a solução.