Temos um banco de dados grande, de cerca de 1 TB, executando o SQL Server 2014 em um servidor poderoso. Tudo funcionou bem por alguns anos. Cerca de duas semanas atrás, fizemos uma manutenção completa, que incluía: Instale todas as atualizações de software; reconstruir todos os índices e compactar arquivos de banco de dados. No entanto, não esperávamos que, em determinado estágio, o uso da CPU do DB aumentasse de 100% a 150% quando a carga real fosse a mesma.
Após muita solução de problemas, reduzimos para uma consulta muito simples, mas não conseguimos encontrar uma solução. A consulta é extremamente simples:
select top 1 EventID from EventLog with (nolock) order by EventID
Leva sempre cerca de 1,5 segundos! No entanto, uma consulta semelhante com "desc" sempre leva cerca de 0 ms:
select top 1 EventID from EventLog with (nolock) order by EventID desc
PTable possui cerca de 500 milhões de linhas; EventID
é a coluna principal do índice em cluster (ordenada ASC
) com o tipo de dados bigint (coluna Identidade). Existem vários threads inserindo dados na tabela na parte superior (EventIDs maiores) e há 1 thread excluindo dados da parte inferior (EventIDs menores).
No SMSS, verificamos que as duas consultas sempre usam o mesmo plano de execução:
Varredura de índice em cluster;
Os números de linha estimados e reais são ambos 1;
O número estimado e real de execuções é 1;
O custo estimado de E / S é 8500 (parece alto)
Se executado consecutivamente, o custo da consulta é o mesmo 50% para ambos.
Atualizei as estatísticas do índice with fullscan
, o problema persistiu; Reconstruí o índice novamente, e o problema parecia ter desaparecido por meio dia, mas voltou.
Ativei as estatísticas de IO com:
set statistics io on
em seguida, executou as duas consultas consecutivamente e encontrou as seguintes informações:
(Para a primeira consulta, a lenta)
Tabela 'PTable'. Contagem de varredura 1, leituras lógicas 407670, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
(Para a segunda consulta, a mais rápida)
Tabela 'PTable'. Contagem de varredura 1, leituras lógicas 4, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
Observe a enorme diferença nas leituras lógicas. O índice é usado nos dois casos.
A fragmentação do índice pode explicar um pouco, mas acredito que o impacto é muito pequeno; e o problema nunca aconteceu antes. Outra prova é se eu executar uma consulta como:
select * from EventLog with (nolock) where EventID=xxxx
Mesmo se eu definir xxxx como os menores EventIDs da tabela, a consulta será sempre muito rápida.
Verificamos e não há nenhum problema de bloqueio / bloqueio.
Nota: Eu apenas tentei simplificar o problema acima. O "PTable" é realmente "EventLog"; o PID
é EventID
.
Eu obter o mesmo teste resultado sem a NOLOCK
dica.
Alguém pode ajudar?
Planos de execução de consulta mais detalhados em XML, da seguinte maneira:
https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob
https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ
Eu não acho que seja importante fornecer a instrução create table. É um banco de dados antigo e está funcionando perfeitamente há muito tempo até a manutenção. Fizemos muitas pesquisas e reduzimos as informações fornecidas na minha pergunta.
A tabela foi criada normalmente com a EventID
coluna como chave primária, que é uma identity
coluna do tipo bigint
. No momento, acho que o problema está na fragmentação do índice. Logo após a reconstrução do índice, o problema parecia ter desaparecido por meio dia; mas por que voltou tão rápido ...?