LATCH_EX aguarda no recurso METADATA_SEQUENCE_GENERATOR

11

Temos um processo que gera um relatório de inventário. No lado do cliente, o processo divide um número configurável de threads de trabalho para criar uma porção de dados para o relatório que corresponde a um repositório dentre muitos (potencialmente milhares, geralmente dezenas). Cada segmento de trabalho chama um serviço da Web que executa um procedimento armazenado.

O processo do banco de dados para processar cada pedaço reúne um monte de dados em uma tabela #Temporary. No final de cada pedaço de processamento, os dados são gravados em uma tabela permanente em tempdb. Finalmente, no final do processo, um encadeamento no lado do cliente solicita todos os dados da tabela tempdb permanente.

Quanto mais usuários executam este relatório, mais lento fica. Analisei a atividade no banco de dados. Em um ponto, vi 35 solicitações separadas, todas bloqueadas em um ponto do processo. Todos esses SPIDs tiveram da ordem de 50 ms esperas do tipo LATCH_EXno recurso METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8). Um SPID possui esse recurso e todos os outros estão bloqueando. Não encontrei nada sobre esse recurso de espera em uma pesquisa na web.

A tabela em tempdb que estamos usando possui uma IDENTITY(1,1)coluna. Esses SPIDs estão aguardando a coluna IDENTITY? Quais métodos podemos usar para reduzir ou eliminar o bloqueio?

O servidor faz parte de um cluster. O servidor está executando o SQL Server 2012 Standard Edition SP1 de 64 bits no Windows 2008 R2 Enterprise de 64 bits. O servidor possui 64 GB de RAM e 48 processadores, mas o banco de dados pode usar apenas 16 porque é a edição padrão.

(Observe que não estou entusiasmado com o design de usar uma tabela permanente no tempdb para armazenar todos esses dados. Mudar isso seria um desafio técnico e político interessante, mas estou aberto a sugestões.)

ATUALIZAÇÃO 23/04/2013

Abrimos um caso de suporte com a Microsoft. Manteremos essa pergunta atualizada à medida que aprendermos mais.

ATUALIZAÇÃO 5/10/2013

O engenheiro de suporte do SQL Server concordou que as esperas foram causadas pela coluna IDENTITY. A remoção da IDENTITY eliminou as esperas. Não foi possível duplicar o problema no SQL 2008 R2; ocorreu apenas no SQL 2012.

Paul Williams
fonte
O processo copia essencialmente os dados das tabelas #Temporary para a tabela permanente ou há uma lógica de transformação adicional acontecendo nessa etapa?
21813 Jon Seigel
Na etapa em que está aguardando, está copiando os registros de inventário de uma única loja para a tabela permanente sem transformação. Poderíamos operar dentro da tabela permanente o tempo todo, mas acho que o programador optou por usar uma tabela #Temporary como área de espera para impedir que atualizações frequentes dos dados se convertam em bloqueios de PAGE.
Paul Williams

Respostas:

4

Supondo que você possa isolar o problema para a geração de valores de identidade (tente remover essa coluna como teste), o que eu recomendaria é o seguinte:

  1. Remova a IDENTITYpropriedade da coluna na tabela final.
  2. Gere valores de identidade em cada uma das tabelas #Temporary.
  3. Ao carregar a tabela final, combine um identificador numérico para a loja específica com os valores de identidade da etapa 2.

Portanto, se você tiver os IDs de loja 3 e 4, acabará com os valores de ID final como este:

3000000001
3000000002
3000000003
...
4000000001
4000000002
...

Ou algo semelhante a isso. Você entendeu a ideia.

Isso eliminará a necessidade de serializar a IDENTITYgeração, preservando a exclusividade no resultado final.

Como alternativa, dependendo de como o processo funciona, insira os valores finais de ID calculados nas #Temporary tables. Em seguida, você pode criar uma exibição que UNION ALLos agrupe, eliminando a necessidade de copiar os dados.

Jon Seigel
fonte
Obrigado pela resposta. Concordo que, se esse for o problema, usar alguma chave fabricada (ou nenhuma chave) pode corrigi-lo. Abrimos um caso com a Microsoft sobre esse problema. Vou postar o resultado aqui e aceitar sua resposta se eles concordarem que esse é o problema.
Paul Williams
@ Paul: Por favor me avise; Eu sou tão curioso. Como você, não consegui encontrar nada na Web sobre essa trava, mas certamente é razoável que seja serialização de identidade / sequência. É difícil dizer se é ou não esse gargalo, embora com mais de 30 threads competindo por valores, parece provável. Você também pode tentar copiar de cada tabela #Temporary em série (em vez de em paralelo) para ver se isso ajuda.
precisa saber é o seguinte
2
O engenheiro do SQL Server concordou que provavelmente era a IDENTITYcoluna. Retiramos o índice já amplo do cluster e removemos completamente a coluna. Não foi necessário. Depois, essas esperas LATCH_EX foram embora. Não foi possível duplicar as esperas no SQL 2008 R2. A questão aconteceu apenas em SQL Server 2012.
Paul Williams
@ Paul: Obrigado por acompanhar. Muito interessante. Suponho que o código que gera IDENTITYvalores foi reescrito para usar o novo material de geração de sequência que era novo em 2012. Em <2012, você pode ver um tipo de trava diferente, embora, se não houvesse nenhum problema de perf, parece que havia uma regressão no código. De qualquer forma, remover a IDENTITYcoluna é a coisa mais segura.
Jon Seigel
Em vez de identidade você pode tentar usar uma 'seqüência' (que é novo no SQL 2012)
Bogdan Maxim
7

(Atualizado em fevereiro de 2019)

Este é um post antigo, que dizia que finalmente consegui convencer a Microsoft de que o fato de isso acontecer é realmente um defeito.

Atualização: a Microsoft confirmou o defeito e atribuiu a ele um bug nº 12628722.

Eu tinha visto este post em novembro de 2018, quando começamos a sofrer o mesmo depois que atualizamos o Sql Server 2005 para o Sql Server 2017. Uma tabela de 3,3 milhões de linhas que costumava levar 10 segundos para inserir em massa começou a tomar 10 minutos em mesas com Identitycolunas.

Acontece que há duas questões por trás disso:

  1. A Microsoft alterou o comportamento no Sql Server 2014 para forçar as inserções em massa a serem paralelizadas - nas versões anteriores, as inserções em massa recebiam um plano serializado.
  2. Depois de funcionar em paralelo em nossa caixa de 32 núcleos, o mecanismo passou mais tempo com os núcleos bloqueando um ao outro do que realmente fazendo o trabalho.

Levei quatro semanas, mas logo após as férias recebi um presente tardio do Papai Noel - confirmação de que o problema era realmente um defeito.

Existem algumas soluções possíveis que encontramos até que isso seja corrigido:

  1. Use Option (MaxDop 1)na consulta para transformar a inserção em massa novamente em um plano serializado.
  2. Mascarar a coluna Identidade lançando-a (por exemplo Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn)
    • isso impede que a propriedade de identidade seja copiada ao usar SELECT...INTO
  3. Remova a coluna de identidade conforme descrito acima.
  4. Altere o modo de compatibilidade do banco de dados para Sql Server 2012 ou inferior para restabelecer um plano serializado.

Atualização: a correção que a MS estará implementando será retornar esses tipos de inserções de volta ao uso de um Serialized plano. Isso está planejado para o Sql Server 2017 CU14 (nenhuma notícia em outras versões do Sql Server - desculpe!). Quando implementado, o Sinalizador de rastreamento 9492 precisará estar ativado, no nível do servidor ou via DBCC TraceOn .

Rachel Ambler
fonte