Dela via


Felsöka tidsgränsfel för frågor

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 ett av följande felmeddelanden:

  • Tidsgränsen har överskridits. Tidsgränsöverskridning uppstod innan åtgärden slutfördes eller servern svarar inte. Instruktionen har avslutats.

  • System.Data.SqlClient.SqlException: Tidsgränsen har överskridits. Tidsgränsöverskridning uppstod innan åtgärden slutfördes eller servern svarar inte.

Förklaring

Dessa fel uppstår på programsidan. Programmet anger ett timeout-värde och om tidsgränsen nås avbryts frågan. På SQL Server-sidan orsakar en frågeavbokning från klientsidan en Attention-händelse, fel 3617 (MSSQLSERVER_3617). Om tidsgränsvä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 timeout-egenskap för anslutning. Det senare styr hur lång tid det tar att vänta på en lyckad anslutning och inte deltar i frågekörningen. Mer information finns i Tidsgränsen för frågor är inte samma som tidsgränsen för anslutningen.

Felsökningsanvisningar

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 timeout-felen. Du kan spåra uppmärksamhetshändelsen tillsammans med de sql_batch_completed utökade händelserna och rpc_completed korrelera dem på samma session_id. Om du observerar 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:

    Kommentar

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

    Name Session_id Sql_text Varaktighet (mikrosekunder) Tidsstämpel
    sql_batch_started 54 Markera … från Kunder WHERE cid = 192937 NULL 2021-09-30 09:50:25.0000
    sql_batch_completed 54 Markera … från Kunder WHERE cid = 192937 29999981 2021-09-30 09:50:55.0000
    Observera! 54 Markera … från Kunder WHERE 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 långsamma frågor i SQL Server

    Kommentar

    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 spårning av utökade händelser (logga in och ansluta händelser med collect_options_text) och kontrollera options_text kolumnen. 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ågeprestandaskillnad 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 timeout-vä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 densamma 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 för anslutning eller inloggning:

  • Tidsgränsen för anslutning överskreds. Tidsgränsen passerades när handskakningen före inloggningen skulle genomföras. Detta kan bero på att handskakningen misslyckades eller på att servern inte kunde svara i tid. Tidsåtgången för att försöka ansluta till servern var: [före inloggning] initiering=23; handskakning=14979;

  • Tidsgränsen har överskridits. Tidsgränsöverskridning uppstod innan åtgärden slutfördes eller servern svarar inte. System.ComponentModel.Win32Exception (0x80004005): Tidsgränsen för vänteåtgärden överskreds.

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änsen för anslutningen. Om du vill felsöka tidsgränser för frågor kan du titta på den här videon.