Solucionar problemas de tempo limite de consulta
Sintomas
Suponha que um aplicativo consulte dados de um banco de dados do SQL Server. Se a consulta não retornar nenhum dado dentro do valor de tempo limite configurado (normalmente 30 segundos), o aplicativo cancelará a consulta e gerará uma destas mensagens de erro:
-
O tempo limite expirou. O tempo limite acabou antes da conclusão da operação ou o servidor não está respondendo. A instrução foi finalizada.
-
System.Data.SqlClient.SqlException: o tempo limite da conexão expirou. O tempo limite acabou antes de conclusão da operação ou o servidor não está respondendo.
Explicação
Esses erros ocorrem no lado do aplicativo. O aplicativo define um valor de tempo limite e, se o tempo limite for atingido, ele cancela a consulta. No lado do SQL Server, um cancelamento de consulta do lado do cliente causa um evento Attention, erro 3617 (MSSQLSERVER_3617). Se o valor de tempo limite no lado do aplicativo for definido como 0 (sem limite de tempo), o Mecanismo de Banco de Dados executará a consulta até que ela seja concluída.
- No .NET Framework System.Data.SqlClient, o valor de tempo limite é definido na propriedade CommandTimeout.
- Na API ODBC, ele é definido por meio do
SQL_ATTR_QUERY_TIMEOUT
atributo na função SQLSetStmtAttr . - Na API do JDBC (Java Database Connectivity), ele é definido por meio do método setQueryTimeout.
- No OLEDB, ele é definido por meio da
DBPROP_COMMANDTIMEOUT
propriedade naDBPROP
estrutura. - No VBA (Excel), ele é definido por meio da propriedade ADODB.Command.CommandTimeout.
O tempo limite da consulta é diferente de uma propriedade de tempo limite da conexão. O último controla quanto tempo esperar por uma conexão bem-sucedida e não está envolvido na execução da consulta. Para obter mais informações, consulte O tempo limite da consulta não é o mesmo que o tempo limite da conexão.
Etapas para solucionar problemas
De longe, o motivo mais comum para tempos limite de consulta são consultas de baixo desempenho. Isso significa que a consulta é executada por mais tempo do que o valor de tempo limite de consulta predefinido. Tornar a consulta mais rápida é o primeiro alvo recomendado da solução de problemas. Veja como verificar consultas:
Use Eventos Estendidos ou Rastreamento SQL para identificar as consultas que causam os erros de tempo limite. Você pode rastrear o evento de atenção junto com os
sql_batch_completed
eventos estendidos erpc_completed
correlacioná-los no mesmosession_id
. Se você observar que um evento concluído é imediatamente seguido por um evento de atenção e a duração do evento concluído corresponde aproximadamente à configuração de tempo limite, você identificou a consulta. Veja um exemplo:Observação
No exemplo, a consulta foi executada
SELECT
por quase exatamente 30 segundos e parou. O evento attention com a mesma ID de sessão indica que a consulta foi cancelada pelo aplicativo.Nome Session_id Sql_text Duração (microssegundos) Timestamp sql_batch_started 54 Selecione… de Clientes ONDE cid = 192937 NULO 2021-09-30 09:50:25.0000 sql_batch_completed 54 Selecione… de Clientes ONDE cid = 192937 29999981 2021-09-30 09:50:55.0000 Atenção 54 Selecione… de Clientes ONDE cid = 192937 40000 2021-09-30 09:50:55.0400 Execute e teste as consultas no SQLCMD ou no SSMS (SQL Server Management Studio).
Se as consultas também forem lentas no SQLCMD e no SSMS, solucione problemas e melhore o desempenho das consultas. Para obter informações detalhadas, consulte Solucionar problemas de consultas de execução lenta no SQL Server
Observação
No SQLCMD e no SSMS, o valor de tempo limite é definido como 0 (sem limite de tempo) e as consultas podem ser testadas e investigadas.
Se as consultas forem rápidas no SQLCMD e no SSMS, mas lentas no lado do aplicativo, altere as consultas para usar as mesmas opções SET usadas no SQLCMD e no SSMS. Compare as opções SET coletando um rastreamento de Eventos Estendidos (logon e conexão de eventos com
collect_options_text
) e verifique aoptions_text
coluna. Veja um exemplo:ALTER EVENT SESSION [setOptions] ON SERVER ADD EVENT sqlserver.existing_connection(SET collect_options_text=(1) ACTION(package0.event_sequence,package0.last_error,sqlos.system_thread_id,sqlserver.context_info,sqlserver.session_id,sqlserver.sql_text)), ADD EVENT sqlserver.login(SET collect_options_text=(1) ACTION(sqlos.system_thread_id,sqlserver.context_info,sqlserver.sql_text))
Para obter mais informações, consulte Solucionar problemas de diferença de desempenho de consulta entre o aplicativo de banco de dados e o SSMS.
Verifique se a
CommandTimeout
configuração é menor que a duração esperada da consulta. Se a configuração do usuário estiver correta e os tempos limite ainda ocorrerem, é devido a um problema de desempenho da consulta. Aqui está um exemplo de código ADO.NET com um valor de tempo limite definido como 10 segundos:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.SqlClient; using System.Data; namespace ConsoleApplication6 { class Program { static void Main() { string ConnectionString = "Data Source=.\sql2019;Integrated Security=SSPI;Initial Catalog=tempdb;"; string queryString = "exec test"; using (SqlConnection connection = new SqlConnection(ConnectionString)) { connection.Open(); SqlCommand command = new SqlCommand(queryString, connection); // Setting command timeout to 10 seconds command.CommandTimeout = 10; //command.ExecuteNonQuery(); try { command.ExecuteNonQuery(); } catch (SqlException e) { Console.WriteLine("Got expected SqlException due to command timeout "); Console.WriteLine(e); } } } } }
O tempo limite da consulta não é o mesmo que o tempo limite da conexão
Um tempo limite de consulta é diferente de um tempo limite de conexão ou tempo limite de login. O tempo limite de conexão ou login ocorre quando a conexão inicial com o servidor de banco de dados atinge um período de tempo limite predefinido. Nesta fase, nenhuma consulta foi enviada ao servidor. Estas mensagens são exemplos de erro de tempo limite de conexão ou login:
-
O tempo limite da conexão expirou. O tempo limite expirou ao tentar consumir a confirmação de handshake de pré-logon. Isso pode ocorrer porque o handshake de pré-logon falhou ou o servidor não pôde responder a tempo. A duração da tentativa de conexão com este servidor foi [Pre-Login] initialization=23; handshake=14979;
-
O tempo limite expirou. O tempo limite acabou antes da conclusão da operação ou o servidor não está respondendo. System.ComponentModel.Win32Exception (0x80004005): a operação de espera atingiu o tempo limite.
O valor do tempo limite da conexão é uma configuração do lado do cliente e normalmente é definido como 15 segundos. Para obter mais informações sobre como solucionar problemas de tempo limite de conexão, consulte solucionar problemas de tempo limite de conexão. Para solução de problemas de tempo limite de consulta, assista a este vídeo.