쿼리 시간 제한 오류 문제 해결

증상

애플리케이션이 SQL Server 데이터베이스의 데이터를 쿼리한다고 가정합니다. 쿼리가 구성된 제한 시간 값(일반적으로 30초) 내에 데이터를 반환하지 않으면 애플리케이션은 쿼리를 취소하고 다음 오류 메시지 중 하나를 생성합니다.

  • 시간 제한이 만료되었습니다. 작업이 완료되기 전에 제한 시간이 초과되었거나 서버가 응답하지 않습니다. 문이 종료되었습니다.

  • System.Data.SqlClient.SqlException: 시간 제한이 만료되었습니다. 작업이 완료되기 전에 제한 시간이 초과되었거나 서버가 응답하지 않습니다.

설명

이러한 오류는 애플리케이션 쪽에서 발생합니다. 애플리케이션은 시간 제한 값을 설정하고 시간 제한에 도달하면 쿼리를 취소합니다. SQL Server 쪽에서 클라이언트 쪽에서 쿼리를 취소하면 주의 이벤트인 오류 3617(MSSQLSERVER_3617)이 발생합니다. 애플리케이션 쪽의 제한 시간 값이 0 (시간 제한 없음)으로 설정된 경우 데이터베이스 엔진은 완료될 때까지 쿼리를 실행합니다.

  • .NET Framework System.Data.SqlClient에서 시간 제한 값은 CommandTimeout 속성에 설정됩니다.
  • ODBC API에서는 SQLSetStmtAttr 함수의 SQL_ATTR_QUERY_TIMEOUT 특성을 통해 설정됩니다.
  • JDBC(Java Database Connectivity) API에서는 setQueryTimeout 메서드를 통해 설정됩니다.
  • OLEDB에서는 DBPROP 구조체의 DBPROP_COMMANDTIMEOUT 속성을 통해 설정됩니다.
  • VBA(Excel)에서는 ADODB.Command.CommandTimeout 속성을 통해 설정됩니다.

쿼리 시간 제한은 연결 시간 제한 속성과 다릅니다. 후자는 성공적인 연결을 기다리는 시간을 제어하며 쿼리 실행에는 관여하지 않습니다. 자세한 내용은 쿼리 시간 제한은 연결 시간 제한과 동일하지 않음을 참조하세요.

문제 해결 단계

지금까지 쿼리 시간 제한의 가장 일반적인 이유는 성능이 저하되는 쿼리입니다. 즉, 쿼리가 미리 정의된 쿼리 제한 시간 값보다 오래 실행됩니다. 쿼리를 더 빠르게 실행하는 것이 문제 해결의 첫 번째 권장 대상입니다. 쿼리 확인 방법은 다음과 같습니다.

  1. 확장 이벤트 또는 SQL 추적을 사용하여 시간 초과 오류를 일으키는 쿼리를 식별합니다. 주의 이벤트를 sql_batch_completedrpc_completed 확장 이벤트와 함께 추적하고 동일한 session_id에서 상관 관계를 지정할 수 있습니다. 완료된 이벤트 바로 뒤에 주의 이벤트가 표시되고 완료된 이벤트의 기간이 대략 시간 제한 설정에 해당하는 경우 쿼리를 식별했습니다. 다음은 예입니다.

    참고

    이 예제에서 SELECT 쿼리는 거의 정확히 30초 동안 실행되고 중지되었습니다. 동일한 세션 ID를 갖는 주의 이벤트는 쿼리가 애플리케이션에 의해 취소되었음을 나타냅니다.

    이름 Session_id Sql_text 기간(마이크로초) Timestamp
    sql_batch_started 54 … from Customers WHERE cid = 192937 NULL 2021-09-30 09:50:25.0000
    Sql_batch_completed 54 … from Customers WHERE cid = 192937 29999981 2021-09-30 09:50:55.0000
    주의 54 … from Customers WHERE cid = 192937 40000 2021-09-30 09:50:55.0400
  2. SQLCMD 또는 SSMS(SQL Server Management Studio)에서 쿼리를 실행하고 테스트합니다.

  3. SQLCMD 및 SSMS에서도 쿼리가 느린 경우 쿼리의 성능을 개선하고 문제를 해결합니다. 자세한 내용은 SQL Server 느리게 실행되는 쿼리 문제 해결을 참조하세요.

    참고

    SQLCMD 및 SSMS에서 시간 제한 값은 0(시간 제한 없음)으로 설정되며 쿼리를 테스트하고 조사할 수 있습니다.

  4. 쿼리가 SQLCMD 및 SSMS에서 빠르지만 응용 프로그램 쪽에서 느린 경우 SQLCMD 및 SSMS에 사용되는 것과 동일한 SET 옵션을 사용하도록 쿼리를 변경합니다. 확장 이벤트 추적(로그인 및 collect_options_text로 이벤트 연결)을 수집하여 SET 옵션을 비교하고 options_text 열을 확인합니다. 다음은 예입니다.

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

    자세한 내용은 데이터베이스 애플리케이션과 SSMS 간의 쿼리 성능 차이 문제 해결을 참조하세요.

  5. CommandTimeout 설정이 예상 쿼리 기간보다 작은지 확인합니다. 사용자의 설정이 올바르고 시간 제한은 여전히 발생하는 경우 쿼리 성능 문제 때문입니다. 시간 제한 값이 10초로 설정된 ADO.NET 코드 예제는 다음과 같습니다.

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

쿼리 시간 제한은 연결 시간 제한과 동일하지 않습니다.

쿼리 시간 제한은 연결 시간 제한 또는 로그인 시간 제한과 다릅니다. 연결 또는 로그인 시간 제한은 데이터베이스 서버에 대한 초기 연결이 미리 정의된 제한 시간에 도달할 때 발생합니다. 이 단계에서는 서버에 쿼리가 제출되지 않았습니다. 이러한 메시지는 연결 또는 로그인 시간 제한 오류의 예입니다.

  • 연결 시간 제한이 만료되었습니다. 사전 로그인 핸드셰이크 승인을 사용하는 동안 시간 초과 기간이 경과했습니다. 이는 사전 로그인 핸드셰이크가 실패했거나 서버가 시간을 거슬러 응답할 수 없기 때문일 수 있습니다. 이 서버에 연결하는 동안 소요된 기간은 [사전 로그인] 초기화=23; 핸드셰이크=14979;이었습니다.

  • 시간 제한이 만료되었습니다. 작업이 완료되기 전에 제한 시간이 초과되었거나 서버가 응답하지 않습니다. System.ComponentModel.Win32Exception (0x80004005): 대기 작업 시간이 초과되었습니다.

연결 시간 제한 값은 클라이언트 쪽 설정이며 일반적으로 15초로 설정됩니다. 연결 시간 제한 문제를 해결하는 방법에 대한 자세한 내용은 연결 시간 제한 문제를 참조하세요. 쿼리 시간 제한 문제 해결은 이 비디오를 시청하세요.