Solución de errores de tiempo de espera de consulta

Resumen

Un error de tiempo de espera de consulta en SQL Server se produce cuando una consulta no devuelve datos antes de que expire el tiempo de espera del comando de la aplicación cliente. A continuación, la aplicación cliente cancela la consulta e informa de "Tiempo de espera expirado". En este artículo se explica cómo confirmar que se ha producido un tiempo de espera de consulta (no un tiempo de espera de conexión), cómo identificar la consulta específica mediante la correlación del attention evento con sql_batch_completed eventos extendidos y , y cómo establecer el tiempo de espera del comando en ADO.NET, ODBC, JDBC, OLE DB y rpc_completed ADO. La causa más común es una consulta lenta, por lo que la corrección recomendada es ajustar la consulta en lugar de generar solo el valor de tiempo de espera. Use este artículo cuando una aplicación notifica errores de tiempo de espera mientras SQL Server registra eventos de atención (error 3617) con una duración que coincide estrechamente con el tiempo de espera configurado.

Síntomas de un error de tiempo de espera de consulta

Supongamos que una aplicación consulta datos de una base de datos de SQL Server. Si la consulta no devuelve ningún dato dentro del valor de tiempo de espera configurado (normalmente 30 segundos), la aplicación cancela la consulta y genera uno de estos mensajes de error:

  • Tiempo de espera agotado. El tiempo de espera transcurrió antes de que se completase la operación, o bien el servidor no responde. Se terminó la instrucción.

  • System.Data.SqlClient.SqlException: tiempo de espera agotado. El tiempo de espera transcurrió antes de que se completase la operación, o bien el servidor no responde.

¿Por qué se producen errores de tiempo de espera de consulta?

Estos errores se producen en el lado de la aplicación. La aplicación establece un valor de tiempo de espera y, si se alcanza el tiempo de espera, cancela la consulta. En el lado de SQL Server, una cancelación de consulta del lado cliente provoca un evento de atención, error 3617 (MSSQLSERVER_3617). Si el valor de tiempo de espera en el lado de la aplicación se establece en 0 (sin límite de tiempo), el Motor de base de datos ejecuta la consulta hasta que se complete, independientemente de cuánto tiempo sea, milisegundos o días.

El valor de tiempo de espera se establece de forma diferente para cada controlador o API de acceso a datos:

El tiempo de espera de consulta es diferente de una propiedad de tiempo de espera de conexión. Este último controla cuánto tiempo esperar una conexión correcta y no está implicado en la ejecución de consultas. Para obtener más información, consulte Tiempo de espera de consulta no es el mismo que el tiempo de espera de conexión.

Pasos para identificar y resolver la consulta que agota el tiempo de espera

El motivo más común para los tiempos de espera de consulta es un rendimiento inferior a las consultas. Esto significa que la consulta se ejecuta más tiempo que el valor de tiempo de espera de consulta predefinido. Haga que la consulta se ejecute más rápido para resolver este problema. A continuación se muestra cómo comprobar las consultas:

  1. Use eventos extendidos o seguimiento de SQL para identificar las consultas que provocan errores de tiempo de espera. Puede realizar un seguimiento del evento de atención junto con los sql_batch_completed eventos extendidos y rpc_completed y correlacionarlos en el mismo session_id. Si observa que un evento completado va seguido inmediatamente de un evento de atención y la duración del evento completado se corresponde aproximadamente con la configuración de tiempo de espera, ha identificado la consulta. Este es un ejemplo:

    Nota:

    En el ejemplo, la SELECT consulta se ejecuta casi exactamente 30 segundos y se detiene. El evento de atención con el mismo identificador de sesión indica que la aplicación canceló la consulta.

    Nombre Session_id Sql_text Duración (microsegundos) Marca de tiempo
    sql_batch_started 54 Seleccione … from Customers WHERE cid = 192937 NULL 2021-09-30 09:50:25.0000
    sql_batch_completed 54 Seleccione … from Customers WHERE cid = 192937 29999981 2021-09-30 09:50:55.0000
    Atención 54 Seleccione … from Customers WHERE cid = 192937 40000 2021-09-30 09:50:55.0400
  2. Ejecute y pruebe las consultas en sqlcmd o en SQL Server Management Studio (SSMS).

  3. Si las consultas también son lentas en sqlcmd y SSMS, solucione problemas y mejore el rendimiento de las consultas. Para obtener información detallada, consulte Solución de problemas de consultas de ejecución lenta en SQL Server.

    Nota:

    En sqlcmd y SSMS, el valor de tiempo de espera se establece en 0 (sin límite de tiempo) y puede probar e investigar las consultas.

  4. Si las consultas son rápidas en sqlcmd y SSMS, pero lentamente en la aplicación, cambie las consultas para usar las mismas opciones SET que se usan en sqlcmd y SSMS. Compare las opciones SET mediante la recopilación de un seguimiento de eventos extendidos (inicio de sesión y conexión de eventos con collect_options_text) y compruebe la options_text columna. Este es un ejemplo:

    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 más información, consulte Solución de problemas de diferencias de rendimiento de consultas entre la aplicación de base de datos y SSMS.

  5. Compruebe si la CommandTimeout configuración es menor que la duración esperada de la consulta. Si la configuración del usuario es correcta y se siguen produciendo tiempos de espera, se debe a un problema de rendimiento de consultas. Este es un ejemplo de código ADO.NET con un valor de tiempo de espera establecido en 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);
                    }
                }
            }
        }
    }
    

El tiempo de espera de consulta no es el mismo que el tiempo de espera de conexión.

Un tiempo de espera de consulta es diferente de un tiempo de espera de conexión o de inicio de sesión. El tiempo de espera de conexión o inicio de sesión se produce cuando la conexión inicial al servidor de bases de datos alcanza un período de tiempo de espera predefinido. En este momento, el cliente no ha enviado ninguna consulta al servidor. Estos mensajes son ejemplos de errores de tiempo de espera de conexión o de tiempo de espera de inicio de sesión:

  • Tiempo de espera de conexión agotado. El período de tiempo de espera transcurrió al intentar consumir la confirmación del protocolo de enlace previo al inicio de sesión. Esto podría deberse a un error en el protocolo de enlace previo al inicio de sesión o a que el servidor no pudo responder a tiempo. El tiempo invertido al intentar conectarse a este servidor fue: [Previo al inicio de sesión] inicialización=23; protocolo de enlace=14979;

  • Tiempo de espera agotado. El tiempo de espera transcurrió antes de que se completase la operación, o bien el servidor no responde. System.ComponentModel.Win32Exception (0x80004005): se agotó el tiempo de espera de la operación wait.

El valor de tiempo de espera de conexión es una configuración del lado cliente y normalmente se establece en 15 segundos. Para obtener más información sobre cómo solucionar el tiempo de espera de conexión, consulte Solución de errores de tiempo de espera de conexión.