針對查詢逾時錯誤進行疑難排解

徵狀

假設應用程式會查詢 SQL Server 資料庫中的資料。 如果查詢未在設定的逾時值內傳回任何資料 (通常為 30 秒),應用程式就會取消查詢並產生下列其中一個錯誤訊息:

  • 逾時已過期。 在作業完成之前超過逾時等待的時間,或是伺服器未回應。 陳述式已終止。

  • System.Data.SqlClient.SqlException: 已超過連接逾時的設定。 在作業完成之前超過逾時等待的時間,或是伺服器未回應。

說明

這些錯誤會在應用程式端發生。 應用程式會設定逾時值,如果達到逾時,則會取消查詢。 在 SQL Server 端,從用戶端取消查詢會造成 Attention 事件,錯誤 3617 (MSSQLSERVER_3617)。 如果應用程式端的逾時值設定為 0 (沒有時間限制) ,Database Engine 會執行查詢,直到完成為止。

查詢逾時與連接逾時屬性不同。 後者會控制等待連接成功的時間長度,而且不涉及查詢執行。 如需詳細資訊,請參閱查詢逾時與連接逾時不同

疑難排解步驟

到目前為止,查詢逾時的最常見原因是查詢效能不佳。 這表示查詢的執行時間超過預先定義的查詢逾時值。 讓查詢執行更快速是疑難排解建議的第一個目標。 查詢的檢查方式如下:

  1. 使用擴充事件SQL 追蹤來識別造成逾時錯誤的查詢。 您可以將 Attention 事件與 sql_batch_completedrpc_completed 擴充事件一起追蹤,並在相同的 session_id 上相互關聯。 如果您觀察到已完成的事件緊接著注意事件,且已完成事件的持續時間大約對應至逾時設定,則您已識別出查詢。 以下為範例:

    注意事項

    在此範例中,SELECT 查詢幾乎剛好執行 30 秒後停止。 具有相同工作階段識別碼的 Attention 事件指出已由應用程式取消查詢。

    名稱 Session_id Sql_text 持續時間 (毫秒) 時間戳記
    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/9/30 09:50:55.0000
    注意 54 選取 … from Customers WHERE cid = 192937 40000 2021/9/30 09:50:55.0400
  2. 在 SQLCMD 或 SQL Server Management Studio (SSMS) 中執行和測試查詢。

  3. 如果 SQLCMD 和 SSMS 中的查詢速度也很慢,請進行疑難排解並改善查詢的效能。 如需詳細資訊,請參閱針對 SQL Server 中執行緩慢的查詢進行疑難解答

    注意事項

    在 SQLCMD 和 SSMS 中,逾時值會設定為 0 (沒有時間限制) 而且可以測試和調查查詢。

  4. 如果 SQLCMD 和 SSMS 中的查詢速度很快,但在應用程式端緩慢,請變更查詢,以使用 SQLCMD 和 SSMS 中所使用的相同 SET 選項 。 比較 SET 選項,方法是收集擴充事件追蹤 (登入並將事件與 collect_options_text 連接),然後檢查 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 設定是否小於預期的查詢持續時間。 如果使用者的設定正確且仍然發生逾時,這是由於查詢效能問題所造成。 以下是 ADO.NET 程式碼範例,其逾時值設定為 10 秒:

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

查詢逾時與連線逾時不同

查詢逾時與連線逾時或登入逾時不同。當資料庫伺服器的初始連線達到預先定義的逾時期間時,就會發生連線或登入逾時。 在此階段中,尚未將任何查詢提交至伺服器。 這些訊息是連線或登入逾時錯誤的範例:

  • 連線逾時已過期。 嘗試取用預先登入交握通知時所經過的逾時期間。 這可能是因為登入前交握失敗,或伺服器無法及時回應。 嘗試連線到此伺服器時所花費的持續時間為 [預先登入] initialization=23;handshake=14979;

  • 逾時已過期。 在作業完成之前超過逾時等待的時間,或是伺服器未回應。 System.ComponentModel.Win32Exception (0x80004005) :等候作業逾時。

連線逾時值是用戶端設定,通常設定為 15 秒。 如需如何針對連線逾時進行疑難排解的詳細資訊,請參閱 針對連線逾時進行疑難排解。 如需查詢逾時疑難排解,請觀看這段 影片