Condividi tramite


Risolvere gli errori di timeout della query

Sintomi

Si supponga che un'applicazione esegua una query dei dati da un database SQL Server. Se la query non restituisce dati entro il valore di timeout configurato (in genere 30 secondi), l'applicazione annulla la query e genera uno di questi messaggi di errore:

  • Timeout scaduto. È trascorso il periodo di timeout prima del completamento dell'operazione oppure il server non risponde. L'istruzione è stata terminata.

  • System.Data.SqlClient.SqlException: timeout scaduto È trascorso il periodo di timeout prima del completamento dell'operazione oppure il server non risponde.

Spiegazione

Questi errori si verificano sul lato dell'applicazione. L'applicazione imposta un valore di timeout e, se questo viene raggiunto, annulla la query. Sul lato SQL Server, un annullamento della query dal lato client causa un evento di attenzione, errore 3617 (MSSQLSERVER_3617). Se il valore di timeout sul lato applicazione è impostato su 0 (nessun limite di tempo), il motore di database esegue la query fino al completamento.

  • In .NET Framework System.Data.SqlClient il valore di timeout viene impostato sulla proprietà CommandTimeout.
  • Nell'API ODBC viene impostato tramite l'attributo SQL_ATTR_QUERY_TIMEOUT nella funzione SQLSetStmtAttr.
  • Nell'API JDBC (Java Database Connectivity) viene impostato tramite il metodo setQueryTimeout.
  • In OLEDB viene impostato tramite la proprietà DBPROP_COMMANDTIMEOUT nella struttura DBPROP.
  • In VBA (Excel) viene impostato tramite la proprietà ADODB.Command.CommandTimeout.

Il timeout delle query è diverso da una proprietà di timeout della connessione. Quest'ultimo controlla il tempo di attesa per una connessione riuscita e non è coinvolto nell'esecuzione di query. Per altre informazioni, vedere Differenza tra timeout della query e timeout della connessione.

Procedura di risoluzione dei problemi

Di gran lunga, il motivo più comune per i timeout delle query è la scarsa prestazione delle query. Ciò significa che la query viene eseguita più a lungo del valore di timeout della query predefinito. Rendere più veloce l'esecuzione della query è il primo obiettivo consigliato per la risoluzione dei problemi. Di seguito è indicato come verificare le query:

  1. Usare eventi estesi o traccia SQL per identificare le query che causano gli errori di timeout. È possibile tracciare l'evento di attenzione insieme agli eventi estesi sql_batch_completed e rpc_completed, e correlarli sullo stesso session_id. Se si osserva che un evento completato è immediatamente seguito da un evento di attenzione e la durata dell'evento completato corrisponde approssimativamente all'impostazione di timeout, la query è stata identificata. Ecco un esempio:

    Nota

    Nell'esempio, la query SELECT è stata eseguita per quasi 30 secondi esatti ed è stata arrestata. L'evento di attenzione con lo stesso ID sessione indica che la query è stata annullata dall'applicazione.

    Nome Session_id Sql_text Durata (microsecondi) Data e ora
    sql_batch_started 54 Selezionare … from Customers WHERE cid = 192937 NULL 30/09/2021 09:50:25.0000
    sql_batch_completed 54 Selezionare … from Customers WHERE cid = 192937 29999981 30/09/2021 09:50:55.0000
    Attenzione 54 Selezionare … from Customers WHERE cid = 192937 40000 30/09/2021 09:50:55.0400
  2. Eseguire e testare le query in SQLCMD o in SQL Server Management Studio (SSMS).

  3. Se le query sono lente anche in SQLCMD e SSMS, risolvere i problemi e migliorare le prestazioni delle query. Per informazioni dettagliate, vedere Risolvere i problemi relativi alle query a esecuzione lenta in SQL Server

    Nota

    In SQLCMD e SSMS il valore di timeout è impostato su 0 (nessun limite di tempo) e le query possono essere testate e analizzate.

  4. Se le query sono veloci in SQLCMD e SSMS, ma sono lente sul lato applicazione, modificare le query in modo che utilizzino le stesse opzioni SET usate in SQLCMD e SSMS. Confrontare le opzioni SET raccogliendo una traccia eventi estesi (account di accesso e connessione degli eventi con collect_options_text) e controllando la colonna options_text. Ecco un esempio:

    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))
    

    Per altre informazioni, vedere Risolvere i problemi relativi alle differenze di prestazioni delle query tra l'applicazione di database e SSMS.

  5. Controllare se l'impostazione CommandTimeout è inferiore alla durata prevista della query. Se l'impostazione dell'utente è corretta e si verificano ancora timeout, è a causa di un problema di prestazioni delle query. Ecco un esempio di codice ADO.NET con un valore di timeout impostato su 10 secondi:

    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);
                    }
                }
            }
        }
    }
    

Il timeout delle query non corrisponde al timeout della connessione

Il timeout di una query è diverso da un timeout di connessione o da un timeout di accesso. Il timeout della connessione o dell'accesso si verifica quando la connessione iniziale al server di database raggiunge un periodo di timeout predefinito. In questa fase non è stata inviata alcuna query al server. Questi messaggi sono esempi di errore di timeout della connessione o dell'accesso:

  • Timeout di connessione scaduto. Il periodo di timeout è scaduto durante il tentativo di utilizzare il riconoscimento dell'handshake di pre-accesso. Questo problema può essere dovuto al fatto che l'handshake di pre-accesso non è riuscito oppure il server non è riuscito a rispondere nel tempo. La durata del tentativo di connessione a questo server è stata [Pre-Login] inizializzazione=23; handshake=14979;

  • Timeout scaduto. È trascorso il periodo di timeout prima del completamento dell'operazione oppure il server non risponde. System.ComponentModel.Win32Exception (0x80004005): Tempo di attesa scaduto.

Il valore di timeout della connessione è un'impostazione lato client ed è in genere impostato su 15 secondi. Per altre informazioni su come risolvere i problemi di timeout della connessione, vedere Risolvere i problemi di timeout della connessione. Per la risoluzione dei problemi relativi al timeout delle query, guardare questo video.