Udostępnij za pośrednictwem


Rozwiązywanie problemów z błędami limitu czasu zapytania

Symptomy

Załóżmy, że aplikacja wysyła zapytania o dane z bazy danych programu SQL Server. Jeśli zapytanie nie zwraca żadnych danych w skonfigurowanej wartości limitu czasu (zazwyczaj 30 sekund), aplikacja anuluje zapytanie i generuje jeden z następujących komunikatów o błędach:

  • Upłynął limit czasu. Limit czasu upłynął przed ukończeniem operacji lub serwer nie odpowiada. Instrukcja została zakończona.

  • System.Data.SqlClient.SqlException: Upłynął limit czasu. Limit czasu upłynął przed ukończeniem operacji lub serwer nie odpowiada.

Wyjaśnienie

Te błędy występują po stronie aplikacji. Aplikacja ustawia wartość limitu czasu, a jeśli limit czasu zostanie osiągnięty, anuluje zapytanie. Po stronie programu SQL Server anulowanie zapytania po stronie klienta powoduje zdarzenie uwagi, błąd 3617 (MSSQLSERVER_3617). Jeśli wartość limitu czasu po stronie aplikacji jest ustawiona na 0 (bez limitu czasu), aparat bazy danych wykonuje zapytanie, dopóki nie zostanie ukończone.

  • W środowisku .NET Framework System.Data.SqlClient wartość limitu czasu jest ustawiana we właściwości CommandTimeout.
  • W interfejsie API ODBC jest ustawiany za pomocą atrybutu SQL_ATTR_QUERY_TIMEOUT w funkcji SQLSetStmtAttr .
  • W interfejsie API JDBC (Java Database Connectivity) jest on ustawiany za pośrednictwem metody setQueryTimeout.
  • W bazie DANYCH OLEDB jest ustawiana za pomocą DBPROP_COMMANDTIMEOUT właściwości w DBPROP strukturze.
  • W programie VBA (Excel) jest on ustawiany za pośrednictwem właściwości ADODB.Command.CommandTimeout.

Limit czasu zapytania różni się od właściwości przekroczenia limitu czasu połączenia. Ten ostatni kontroluje czas oczekiwania na pomyślne połączenie i nie jest zaangażowany w wykonywanie zapytań. Aby uzyskać więcej informacji, zobacz Limit czasu zapytania nie jest taki sam jak limit czasu połączenia.

Kroki rozwiązywania problemów

Zdecydowanie najczęstszą przyczyną przekroczenia limitu czasu zapytania jest niedosytywanie zapytań. Oznacza to, że zapytanie działa dłużej niż wstępnie zdefiniowana wartość limitu czasu zapytania. Szybsze uruchamianie zapytania jest zalecanym pierwszym celem rozwiązywania problemów. Poniżej przedstawiono sposób sprawdzania zapytań:

  1. Użyj zdarzeń rozszerzonych lub śledzenia SQL, aby zidentyfikować zapytania, które powodują błędy przekroczenia limitu czasu. Zdarzenie uwagi można śledzić wraz z zdarzeniami rozszerzonymi sql_batch_completed i rpc_completed i skorelować je na tym samym session_idobiekcie . Jeśli zauważysz, że zdarzenie zakończone jest natychmiast po zdarzeniu uwagi, a czas trwania ukończonego zdarzenia odpowiada w przybliżeniu ustawieniu limitu czasu, zidentyfikowano zapytanie. Oto przykład:

    Uwaga 16.

    W tym przykładzie SELECT zapytanie trwało prawie dokładnie 30 sekund i zatrzymało. Zdarzenie uwagi o tym samym identyfikatorze sesji wskazuje, że zapytanie zostało anulowane przez aplikację.

    Nazwisko Session_id Sql_text Czas trwania (mikrosekundy) Sygnatura czasowa
    sql_batch_started 54 Wybierz … from Customers WHERE cid = 192937 NULL 2021-09-30 09:50:25.0000
    sql_batch_completed 54 Wybierz … from Customers WHERE cid = 192937 29999981 2021-09-30 09:50:55.0000
    Uwaga 54 Wybierz … from Customers WHERE cid = 192937 40000 2021-09-30 09:50:55.0400
  2. Wykonaj i przetestuj zapytania w programie SQLCMD lub w programie SQL Server Management Studio (SSMS).

  3. Jeśli zapytania są również powolne w usługach SQLCMD i SSMS, rozwiąż problemy i zwiększ wydajność zapytań. Aby uzyskać szczegółowe informacje, zobacz Rozwiązywanie problemów z powolnymi zapytaniami w programie SQL Server

    Uwaga 16.

    W usługach SQLCMD i SSMS wartość limitu czasu jest ustawiona na 0 (bez limitu czasu), a zapytania można przetestować i zbadać.

  4. Jeśli zapytania są szybkie w usługach SQLCMD i SSMS, ale powolne po stronie aplikacji, zmień zapytania tak, aby używały tych samych opcji ZESTAWU używanych w usługach SQLCMD i SSMS. Porównaj opcje SET, zbierając ślad zdarzeń rozszerzonych (identyfikator logowania i łączenia zdarzeń za pomocą collect_options_textpolecenia ) i sprawdzając kolumnę options_text . Oto przykład:

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

    Aby uzyskać więcej informacji, zobacz Rozwiązywanie problemów z różnicą wydajności zapytań między aplikacją bazy danych i programem SSMS.

  5. Sprawdź, CommandTimeout czy ustawienie jest mniejsze niż oczekiwany czas trwania zapytania. Jeśli ustawienie użytkownika jest poprawne, a limity czasu nadal występują, wynika to z problemu z wydajnością zapytań. Oto przykład kodu ADO.NET z wartością limitu czasu ustawioną na 10 sekund:

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

Przekroczenie limitu czasu zapytania nie jest takie samo jak przekroczenie limitu czasu połączenia

Limit czasu zapytania różni się od limitu czasu połączenia lub przekroczenia limitu czasu logowania. Przekroczenie limitu czasu połączenia lub logowania występuje, gdy początkowe połączenie z serwerem bazy danych osiągnie wstępnie zdefiniowany limit czasu. Na tym etapie żadne zapytanie nie zostało przesłane do serwera. Te komunikaty to przykłady błędu przekroczenia limitu czasu połączenia lub logowania:

  • Upłynął limit czasu połączenia. Podczas próby wykorzystania potwierdzenia uzgodnienia przed logowaniem upłynął limit czasu. Może to być spowodowane tym, że uzgadnianie przed logowaniem nie powiodło się lub serwer nie mógł odpowiedzieć na czas. Zużycie czasu podczas próby nawiązania połączenia z tym serwerem: [przed logowaniem] inicjowanie=23; uzgadnianie=14979;

  • Upłynął limit czasu. Limit czasu upłynął przed ukończeniem operacji lub serwer nie odpowiada. System.ComponentModel.Win32Exception (0x80004005): Upłynął limit czasu operacji oczekiwania.

Wartość limitu czasu połączenia jest ustawieniem po stronie klienta i zazwyczaj jest ustawiona na 15 sekund. Aby uzyskać więcej informacji na temat rozwiązywania problemów z limitem czasu połączenia, zobacz Rozwiązywanie problemów z limitem czasu połączenia. Aby uzyskać informacje o rozwiązywaniu problemów z przekroczeniem limitu czasu zapytania, obejrzyj ten film wideo.