Felsöka tidsgräns-fel för fråga

Symptom

Anta att ett program frågar efter data från en SQL Server-databas. Om frågan inte returnerar några data inom det konfigurerade tidsgränsvärdet (vanligtvis 30 sekunder) avbryter programmet frågan och genererar något av följande felmeddelanden:

  • Tidsgränsen har upphört att gälla. Tidsgränsen nåddes innan åtgärden slutfördes, eller så svarar inte servern. Instruktionen har avslutats.

  • System.Data.SqlClient.SqlException: Tidsgränsen har upphört att gälla. Tidsgränsen nåddes innan åtgärden slutfördes, eller så svarar inte servern.

Förklaring

Dessa fel uppstår på programsidan. Programmet anger ett tidsgränsvärde och om tidsgränsen nås avbryts frågan. På SQL Server-sidan orsakar en frågeavbokning från klientsidan en uppmärksamhetshändelse, fel 3617 (MSSQLSERVER_3617). Om timeout-värdet på programsidan är inställt på 0 (ingen tidsgräns) kör databasmotorn frågan tills den har slutförts.

Tidsgränsen för frågor skiljer sig från en tidsgräns-egenskap för anslutning. Det senare styr hur lång tid det tar att vänta på en lyckad anslutning och ingår inte i frågekörningen. Mer information finns i Tidsgränsen för frågor är inte samma som tidsgränsen för anslutning.

Felsökningssteg

Den överlägset vanligaste orsaken till tidsgränser för frågor är underpresterande frågor. Det innebär att frågan körs längre än det fördefinierade tidsgränsvärdet för frågan. Att köra frågan snabbare är det rekommenderade första målet för felsökningen. Så här kontrollerar du frågor:

  1. Använd Extended Events eller SQL Trace för att identifiera de frågor som orsakar tidsgräns-felen. Du kan spåra uppmärksamhetshändelsen tillsammans med sql_batch_completed och rpc_completed utökade händelser och korrelera dem på samma session_id. Om du ser att en slutförd händelse omedelbart följs av en uppmärksamhetshändelse, och varaktigheten för den slutförda händelsen motsvarar ungefär tidsgränsinställningen, har du identifierat frågan. Här är ett exempel:

    Obs!

    I exemplet kördes frågan SELECT i nästan exakt 30 sekunder och stoppades. Uppmärksamhetshändelsen med samma sessions-ID anger att frågan avbröts av programmet.

    Namn Session_id Sql_text Varaktighet (mikrosekunder) Tidsstämpel
    sql_batch_started 54 Välj … från kunder där cid = 192937 NULL 2021-09-30 09:50:25.0000
    Sql_batch_completed 54 Välj … från kunder där cid = 192937 29999981 2021-09-30 09:50:55.0000
    Obs! 54 Välj … från kunder där cid = 192937 40000 2021-09-30 09:50:55.0400
  2. Kör och testa frågorna i SQLCMD eller i SQL Server Management Studio (SSMS).

  3. Om frågorna också är långsamma i SQLCMD och SSMS kan du felsöka och förbättra frågornas prestanda. Detaljerad information finns i Felsöka frågor som körs långsamt i SQL Server

    Obs!

    I SQLCMD och SSMS anges tidsgränsvärdet till 0 (ingen tidsgräns) och frågorna kan testas och undersökas.

  4. Om frågorna är snabba i SQLCMD och SSMS, men är långsamma på programsidan, ändrar du frågorna så att de använder samma SET-alternativ som används i SQLCMD och SSMS. Jämför SET-alternativen genom att samla in en Extended Events-spårning (logga in och ansluta händelser med collect_options_text) och kontrollera kolumnen options_text. Här är ett exempel:

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

    Mer information finns i Felsöka frågeprestandaskillnader mellan databasprogram och SSMS.

  5. Kontrollera om inställningen CommandTimeout är mindre än den förväntade frågevaraktigheten. Om användarens inställning är korrekt och tidsgränser fortfarande inträffar beror det på ett problem med frågeprestanda. Här är ett ADO.NET-kodexempel med ett tidsgränsvärde inställt på 10 sekunder:

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

Tidsgränsen för frågan är inte samma som tidsgränsen för anslutningen

Tidsgränsen för en fråga skiljer sig från tidsgränsen för anslutningen eller tidsgränsen för inloggning. Tidsgränsen för anslutning eller inloggning inträffar när den första anslutningen till databasservern når en fördefinierad tidsgräns. I det här skedet har ingen fråga skickats till servern. Dessa meddelanden är exempel på timeout-fel vid anslutning eller inloggning:

  • Tidsgränsen för inloggning har upphört att gälla. Tidsgränsen uppnåddes vid försök att använda handskakningsbekräftelse före inloggning. Det kan bero på att handskakningen före inloggningen misslyckades eller att servern inte kunde svara bakåt i tiden. Varaktigheten för att försöka ansluta till den här servern var [Pre-Login] initiering=23. Handskakning=14979.

  • Tidsgränsen har upphört att gälla. Tidsgränsen nåddes innan åtgärden slutfördes, eller så svarar inte servern. System.ComponentModel.Win32Exception (0x80004005): vänteåtgärden nådde sin tidsgräns.

Tidsgränsvärdet för anslutningen är en inställning på klientsidan och är vanligtvis inställd på 15 sekunder. Mer information om hur du felsöker tidsgränsen för anslutning finns i Felsöka tidsgräns för anslutning. Titta på den här videon för felsökning av tidsgränser för frågor.