Decidimos testar e talvez implementar o novo query_abort
rastreamento de eventos estendido em todos os nossos servidores de banco de dados para saber mais sobre nossas consultas de tempo limite. Atualmente, utilizamos o rpc_completed
evento com status=2
filtro.
Usaremos a ferramenta SQLCallStackResolver conforme detalhado neste vídeo da Microsoft e usaremos a task_callstack_rva
coluna processada pela ferramenta.
Aqui está um dos vestígios que temos de uma SELECT
declaração:
00 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01 YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
00 SqlDK!ThreadScheduler::SwitchWorker
01 SqlDK!SOS_Scheduler::Switch
02 SqlDK!SOS_Scheduler::SuspendNonPreemptive
03 SqlDK!WaitableBase::Wait
04 sqllang!TDSSNIClient::WriteStatus
05 sqllang!WaitOnWriteAsyncToFinish
06 sqllang!write_data
07 sqllang!flush_buffer
08 sqllang!CTds74::SendRowImpl
09 SqlTsEs!CEsExec::GeneralEval4
0a sqllang!CXStmtQuery::ErsqExecuteQuery
0b sqllang!CXStmtSelect::XretExecute
0c sqllang!CExecStmtLoopVars::ExecuteXStmtAndSetXretReturn
0d sqllang!CMsqlExecContext::ExecuteStmts<1,0>
0e sqllang!CMsqlExecContext::FExecute
0f sqllang!CSQLSource::Execute
10 sqllang!process_request
11 sqllang!process_commands_internal
12 sqllang!process_messages
13 SqlDK!SOS_Task::Param::Execute
14 SqlDK!SOS_Scheduler::RunTask
15 SqlDK!SOS_Scheduler::ProcessTasks
16 SqlDK!Worker::EntryPoint
17 SqlDK!ThreadScheduler::RunWorker
18 SqlDK!SystemThreadDispatcher::ProcessWorker
19 SqlDK!SchedulerManager::ThreadEntryPoint
<frame id="28" address="0x776D11E7" />
1d WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
1e ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
Pelo que entendi, a consulta está sendo processada e entra em vários estados e esperas, como atribuição a um agendador, por exemplo. Mas como essas informações nos ajudam a entender o que causou o tempo limite? Na verdade, parece-me que tudo está indo bem.
Uma pilha de chamadas não possui nenhum contexto (você não pode ver o estado de nada), é apenas o caminho que o thread percorreu como parte desse programa. Às vezes, isso é útil, às vezes não.
Nesse caso, a pilha de chamadas é bastante benigna, você está correto. Você terá que usar seu poder lógico de dedução para descobrir o que pode ter acontecido com base no aplicativo cliente, nos logs SQL e em quaisquer outros dados disponíveis que possam ajudar.
Quadros
0x19
-0x13
são execução de tarefas padronizadas.Quadros
0x12
-0x10
são o padrão para processar solicitações recebidas no servidor.Frames
0x0f
-0x0a
estão apenas processando uma instrução select de uma fonte de idioma.Frames
0x08
-0x03
estão enviando dados de volta ao cliente e aguardando o envio dos dados ou uma confirmação de recebimento.Quadros
0x02
-0x00
movem esse trabalhador para forarunning
e parasuspended
(espera) enquanto trocam um novorunnable
trabalhador (ou oidle
thread, se não houverrunnable
itens).Se você fizesse algumas suposições com base nos dados acima sem contexto, pode ser que a conexão tenha sido interrompida, o cliente (ou driver) enviou uma atenção, a espera no IO demorou muito e expirou, o que foi abortado em si, etc.
Como isso ajuda? Não tenho certeza, depende de quantos dados você coletou do cliente ou de outras ferramentas. Assim como uma captura de rede, obter dados apenas de um lado geralmente não é muito útil; você precisará de dados de ambos os lados ao mesmo tempo para entender o que cada lado pensou e onde/por que o problema pode estar ocorrendo.