2011-12-05 188 views
3

我在SQL Server中創建了一個存儲過程,該存儲過程從Management Studio中立即運行。通過ado.net從C#調用SQL Server存儲過程超時

從代碼調用存儲過程時,使用完全相同的參數,超時。

存儲過程接受許多參數,大多數參數的默認值爲NULL。我曾嘗試用多種方法的參數分配SqlCommand對象:爲空值

  • 不加參數
  • 添加參數爲空值,並通過作爲一個值DBNull.Value
  • 使用SQLCommandBuilder.DeriveParameters並且僅分配非空值

Sp除其他參數外還有2個datetime參數。當這些日期的範圍很小時,查詢會運行,但對於較大的範圍(大約3個月左右),當我嘗試執行ExecuteReader方法時,我會得到一個SqlException - Timeout expired。要返回的行數不多(大約3500)。

在努力,看看有什麼與工藝發生的事情,我運行下面的查詢時ExecuteReader方法開始運行

SELECT st.text AS [SQL Text], 
     w.session_id, 
     w.wait_duration_ms, 
     w.wait_type, w.resource_address, 
     w.blocking_session_id, 
     w.resource_description 
FROM sys.dm_os_waiting_tasks AS w 
INNER JOIN sys.dm_exec_connections AS c ON w.session_id = c.session_id 
CROSS APPLY (SELECT * FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS st 
WHERE w.session_id > 50 
    AND w.wait_duration_ms > 0 

,我得到這樣的結果如下。這是正常的嗎?

SQL Text session_id wait_duration_ms wait_type resource_address blocking_session_id resource_description 
CREATE PROCEDURE [dbo].[GetVoucherJobs]... 64 23993 CXPACKET 0x000000008012A870 64 exchangeEvent id=port801283d0 nodeId=0 
CREATE PROCEDURE [dbo].[GetVoucherJobs]... 64 15 IO_COMPLETION NULL NULL NULL 
CREATE PROCEDURE [dbo].[GetVoucherJobs]... 64 15 IO_COMPLETION NULL NULL NULL 
CREATE PROCEDURE [dbo].[GetVoucherJobs]... 64 2121 CXPACKET 0x000000008012BE60 64 exchangeEvent id=port801283d0 nodeId=0 

如果不是調用存儲過程,我跑通過CommandText設置爲SP的身體立即運行查詢。這是我的存儲過程:

CREATE PROCEDURE [dbo].[GetVoucherJobs] 
    @sUsrClientCode NVARCHAR(50), 
    @dFr DATETIME = NULL, 
    @dTo DATETIME = NULL, 
    @sVchSerial NVARCHAR(50) = NULL, 
    @sConName NVARCHAR(50) = NULL, 
    @sJobOrderId NVARCHAR(50) = NULL, 
    @sUsrName NVARCHAR(50) = NULL, 
    @bJobClosed BIT = NULL, 
    @bJobCanceled BIT = NULL, 
    @bCount BIT = 0, 
    @bGTCostCenter BIT = 0 
AS 
BEGIN 
    SET NOCOUNT ON 

    IF @bCount = 0 
    BEGIN 
     IF @bGTCostCenter = 0 
     BEGIN 
      SELECT CASE WHEN sfVchBelongsTo IS NULL THEN sVchSerial ELSE sfVchBelongsTo END, Jobs.*, 
       nkVch, sVchConName, sVchConAddress, sVchConCity, sVchConTel, sVchConZip, sVchDest, sVchCourier, 
       sVchSerial, nVchPieces, cVchWeight, sVchDesc, sVchAdditional, cVchTotal, sVchStatus, 
       sVchSubCode, sfVchBelongsTo, cVchInsAmount, nfVchJob, sUsrName 
      FROM Jobs 
      INNER JOIN Users ON nfJobUser = nkUsr 
      INNER JOIN Vouchers ON nfVchJob = nkJob 
      WHERE nfVchLinkedTo IS NULL AND 
      sUsrClientCode = @sUsrClientCode AND 
      (@dFr IS NULL OR dJob >= @dFr) AND 
      (@dTo IS NULL OR dJob <= @dTo) AND 
      (@sVchSerial IS NULL OR sVchSerial LIKE (@sVchSerial + '%')) AND 
      (@sConName IS NULL OR sVchConName LIKE (@sConName + '%')) AND 
      (@sJobOrderId IS NULL OR sJobOrderId LIKE (@sJobOrderId + '%')) AND 
      (@sUsrName IS NULL OR sUsrName = @sUsrName) AND 
      (@bJobClosed IS NULL OR bJobClosed = @bJobClosed) AND 
      (@bJobCanceled IS NULL OR bJobCanceled = @bJobCanceled) 
      ORDER BY 1, nkJob 
     END 
     ELSE 
     BEGIN 
      SELECT CASE WHEN sfVchBelongsTo IS NULL THEN sVchSerial ELSE sfVchBelongsTo END, Jobs.*, 
       nkVch, sVchConName, sVchConAddress, sVchConCity, sVchConTel, sVchConZip, sVchDest, sVchCourier, 
       sVchSerial, nVchPieces, cVchWeight, sVchDesc, sVchAdditional, cVchTotal, sVchStatus, 
       COALESCE(κωδικος, '') AS sVchSubCode, sfVchBelongsTo, cVchInsAmount, nfVchJob, sUsrName 
      FROM Jobs 
      INNER JOIN Users ON nfJobUser = nkUsr 
      INNER JOIN Vouchers ON nfVchJob = nkJob 
      LEFT JOIN _ΠΕΛΑΤΕΣ_ΚΕΝΤΡΑ_ΧΡΕΩΣΗΣ ON sVchSubCode = Περιγραφη AND Πελατης = sUsrClientCode 
      WHERE nfVchLinkedTo IS NULL AND 
      sUsrClientCode = @sUsrClientCode AND 
      (@dFr IS NULL OR dJob >= @dFr) AND 
      (@dTo IS NULL OR dJob <= @dTo) AND 
      (@sVchSerial IS NULL OR sVchSerial LIKE (@sVchSerial + '%')) AND 
      (@sConName IS NULL OR sVchConName LIKE (@sConName + '%')) AND 
      (@sJobOrderId IS NULL OR sJobOrderId LIKE (@sJobOrderId + '%')) AND 
      (@sUsrName IS NULL OR sUsrName = @sUsrName) AND 
      (@bJobClosed IS NULL OR bJobClosed = @bJobClosed) AND 
      (@bJobCanceled IS NULL OR bJobCanceled = @bJobCanceled) 
      ORDER BY 1, nkJob 
     END 
    END 
    ELSE 
    BEGIN 
     SELECT COUNT(*) FROM Jobs 
     INNER JOIN Users ON nfJobUser = nkUsr 
     INNER JOIN Vouchers ON nfVchJob = nkJob 
     WHERE nfVchLinkedTo IS NULL AND 
     sUsrClientCode = @sUsrClientCode AND 
     (@dFr IS NULL OR dJob >= @dFr) AND 
     (@dTo IS NULL OR dJob <= @dTo) AND 
     (@sVchSerial IS NULL OR sVchSerial LIKE (@sVchSerial + '%')) AND 
     (@sConName IS NULL OR sVchConName LIKE (@sConName + '%')) AND 
     (@sJobOrderId IS NULL OR sJobOrderId LIKE (@sJobOrderId + '%')) AND 
     (@sUsrName IS NULL OR sUsrName = @sUsrName) AND 
     (@bJobClosed IS NULL OR bJobClosed = @bJobClosed) AND 
     (@bJobCanceled IS NULL OR bJobCanceled = @bJobCanceled) 
    END 
END 

我發現了一個類似的問題,但沒有答案: Asp.Net Gives a Timeout Error While Running a Stored Procedure

下面是代碼:

SqlCommand oCommand = new SqlCommand("GetVoucherJobs"); 
SqlConnection oConnection; 
Result eResult = OpenConnection(out oConnection); 
if(eResult != Result.Ok) return new GetJobsResult { eResult = eResult }; 

oCommand.CommandType = CommandType.StoredProcedure; 
oCommand.Connection = oConnection; 
oCommand.Parameters.AddWithValue("@sUsrClientCode", oParams.ClientCode); 
oCommand.Parameters.AddWithValue("@dFr", oParams.DateFrom == Utils.dNull ? Utils.dNull : oParams.DateFrom); 
oCommand.Parameters.AddWithValue("@dTo", oParams.DateTo == Utils.dNull ? DateTime.MaxValue : oParams.DateTo); 
oCommand.Parameters.Add("@sVchSerial", SqlDbType.NVarChar); 
if(oParams.VoucherNumber != "") oCommand.Parameters["@sVchSerial"].Value = oParams.VoucherNumber; 
oCommand.Parameters.Add("@sConName", SqlDbType.NVarChar); 
if(oParams.ConsigneeName != "") oCommand.Parameters["@sConName"].Value = oParams.ConsigneeName; 
oCommand.Parameters.Add("@sUsrName", SqlDbType.NVarChar); 
if(oParams.UserName != "") oCommand.Parameters["@sUsrName"].Value = oParams.UserName; 
oCommand.Parameters.Add("@sJobOrderId", SqlDbType.NVarChar); 
if(oParams.OrderId != "") oCommand.Parameters["@sJobOrderId"].Value = oParams.OrderId; 
oCommand.Parameters.Add("@bJobClosed", SqlDbType.Bit); 
oCommand.Parameters.Add("@bJobCanceled", SqlDbType.Bit); 
if(oParams.State != VoucherState.All) { 
    oCommand.Parameters["@bJobClosed"].Value = oParams.State == VoucherState.Open ? 0 : 1; 
    if(oParams.State == VoucherState.ClosedActive || oParams.State == VoucherState.ClosedCanceled) { 
     oCommand.Parameters["@bJobCanceled"].Value = oParams.State == VoucherState.ClosedActive ? 0 : 1; 
    } 
} 
oCommand.Parameters.AddWithValue("@bGTCostCenter", oParams.UseGTCostCenter); 
oCommand.Parameters.AddWithValue("bCount", 0); 

SqlDataReader oReader = oCommand.ExecuteReader(); 
+1

有幾件事情要嘗試:1)立即讓存儲過程返回;如果來自ado.net的電話仍然超時,那麼你知道一些非常可怕的事情正在發生。如果是這種情況,那麼確保SQL Server 2005使用最新的服務包進行了修補(或者使用sql server 2008 express進行嘗試) - 我之前已經看到過這種行爲(在sql 2000上) – wal

+0

請顯示您用來調用程序 –

+0

@wal我會將生產數據庫恢復到本地副本,並希望得到相同的結果,以便測試RETURN事情。現在我正在使用最新的服務包(SP4)。 – alfoks

回答

1

如果你從Management Studio中不同的結果,它可能是你的一些連接設置不同 - 例如ANSI_NULLS,ANSI_PADDING。

嘗試在SP中明確設置它們 - 這可能會幫助您在Management Studio和.NET中獲得相同的行爲,這將有助於診斷。

+0

你是對的!在此之前顯示, http://www.mssqltips.com/sqlservertip/1304/reproducing-sql-server-query-execution-plan-performance-problems/ 但我確定不是這樣。事實證明,在相同的設置下,管理工作室需要花費很多才能完成。這並不能解決我的問題,但至少我知道在哪裏尋找。謝謝! – alfoks

+0

當我設置arithabort它立即完成。所以我只需要找出發生溢出的位置。 – alfoks

+0

最終這個問題是由於參數嗅探引起的 http://www.simple-talk.com/sql/t-sql-programming/parameter-sniffing/ 我不知道爲什麼設置arithabort開啓,解決了問題。我的猜測是,通過設置選項,存儲過程現金將被清除,因此sp會重新編譯並運行正常。 – alfoks

相關問題