2013-01-03 69 views
13

我試圖從我的C#web應用程序中運行插入查詢。當我從SQL Server Management Studio運行查詢時,插入查詢大約需要五分鐘才能完成。當從應用程序運行時,它會在三十分鐘後超時(是分鐘而不是秒)。在C#web應用程序中插入查詢超時,從SQL Server Management Studio運行正常

我已經從VS調試器中抓取了實際的SQL語句,並從Mgmt Studio中運行它,它工作正常。

所有這些都是從我的開發環境運行,而不是生產環境。查詢過程中沒有其他SQL Server活動。我正在使用SQL Server 2008 R2進行開發。 MS VS 2010 Express,Asp.Net 4.0。 SQL Server的管理工作室10

也有同樣的問題,這是從來沒有回答:SQL server timeout 2000 from C# .NET

這裏的SET選項從:DBCC USEROPTIONS

Option     MgtStudio  Application 
----------------------- -------------- -------------- 
textsize    2147483647  -1 
language    us_english  us_english 
dateformat    mdy   mdy 
datefirst    7    7 
lock_timeout   -1    -1 
quoted_identifier  SET   SET 
arithabort    SET   NOT SET 
ansi_null_dflt_on  SET   SET 
ansi_warnings   SET   SET 
ansi_padding   SET   SET 
ansi_nulls    SET   SET 
concat_null_yields_null SET   SET 
isolation level   read committed read committed 

只有TEXTSIZE和ARITHABORT是不同的。

任何想法,爲什麼在查詢執行時間有這樣的差異,我可以做些什麼來縮小差異?

我不確定包括查詢在內會有多大用處,特別是因爲包含模式太多了。無論如何,那就是:

INSERT INTO GeocacherPoints 
      (CacherID, 
      RegionID, 
      Board, 
      Control, 
      Points) 
SELECT z.CacherID, 
     z.RegionID, 
     z.Board, 
     21, 
     z.Points 
FROM (SELECT CacherID, 
       gp.RegionID, 
       Board=gp.Board + 10, 
       (CASE 
        WHEN (SELECT COUNT(*) 
         FROM Geocache g 
           JOIN GeocacheRegions r 
            ON (r.CacheID = g.ID) 
         WHERE r.RegionID = gp.RegionID 
           AND g.FinderPoints >= 5) < 20 THEN NULL 
        ELSE (SELECT SUM(y.FinderPoints)/20 
         FROM (SELECT x.FinderPoints, 
             ROW_NUMBER() OVER (ORDER BY x.FinderPoints DESC, x.ID) AS Row 
           FROM (SELECT g.FinderPoints, 
               g.ID 
             FROM Geocache g 
               JOIN Log l 
                ON (l.CacheID = g.ID) 
               JOIN Geocacher c 
                ON (c.ID = l.CacherID) 
               JOIN GeocacheRegions r 
                ON (r.CacheID = g.ID) 
             WHERE YEAR(l.LogDate) = @Year 
               AND g.FinderPoints >= 5 
               AND c.ID = gp.CacherID 
               AND r.RegionID = gp.RegionID) x) y 
         WHERE y.Row <= 20) 
       END) Points 
     FROM GeocacherPoints gp 
       JOIN Region r 
       ON r.RegionID = gp.RegionID 
     WHERE gp.Control = 21 
       AND r.RegionType IN ('All', 'State') 
       AND gp.Board = @Board - 10) z 
WHERE z.Points IS NOT NULL 
     AND z.Points >= 1 
+3

我剛剛回答,但我意識到你說過30分鐘後超時,而不是秒;這是正確的數字還是它是一個錯字(即30秒後超時而不是分鐘)? –

+0

嘗試指定插入記錄時在表中聲明的參數的確切類型。 – Sunny

+0

是的,30分鐘! – Russ

回答

6

ARITHABORT經常被誤診爲原因。

事實上,從2005年版本開始ANSI_WARNINGS(因爲它在兩個連接中),ARITHABORT無論如何都是隱含的,並且此設置沒有實際效果。

但是它確實有副作用。爲了允許ANSI_WARNINGS關閉的情況,ARITHABORT的設置被用作plan cache keys之一,這意味着具有不同設置的會話不能共享彼此的計劃。

當您在SSMS中運行查詢時,無法重新使用爲您的應用程序緩存的執行計劃,除非它們都具有相同的計劃緩存鍵,因此它會編譯一個新計劃以「嗅探」當前正在測試的參數值。您的應用程序計劃可能會針對不同的參數值進行編譯。這個問題被稱爲「參數嗅探」。

可檢索和兩個執行計劃的東西,如

SELECT usecounts, cacheobjtype, objtype, text, query_plan, value as set_options 
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) 
cross APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa 
where text like '%INSERT INTO GeocacherPoints (CacherID,RegionID,Board,Control,Points)%' 
and attribute='set_options' and text not like '%this query%' 

XML中的參數部分告訴你參數的編譯時間值進行比較。

查看Slow in the Application, Fast in SSMS? Understanding Performance Mysteries瞭解更多信息。

執行計劃

您提供的估計的執行計劃,而不是實際的執行計劃,但可以看出,只有第一個查詢計劃是參數,它被編譯爲下面的值。

 <ParameterList> 
      <ColumnReference Column="@Dec31" ParameterCompiledValue="'2013-12-31'" /> 
      <ColumnReference Column="@Jan1" ParameterCompiledValue="'2013-01-01'" /> 
      <ColumnReference Column="@Board" ParameterCompiledValue="(71)" /> 
     </ParameterList> 

第二執行計劃使用變量而非參數。這顯着改變了事情。

DECLARE @Board INT 
DECLARE @Jan1 DATE 
DECLARE @Dec31 DATE 

SET @Board=71 
SET @Jan1='January 1, 2013' 
SET @Dec31='December 31, 2013' 

INSERT INTO GeocacherPoints 

SQL Server不嗅出變量的具體數值,併產生類似於使用OPTIMIZE FOR UNKNOWN暗示通用計劃。該計劃中的估計行數遠高於第一個計劃。

你沒有說明哪個是快速計劃,哪個是慢速計劃。如果使用變量的速度更快,那麼您可能需要更新統計數據,如果使用參數的速度更快,那麼您可能會遇到這裏描述的問題Statistics, row estimations and the ascending date column,那麼您將能夠實現變量嗅探並使其考慮實際變量值使用OPTION (RECOMPILE)提示。

+0

這是一篇有趣的文章。執行時間的差異開始給我帶來某種意義上的感覺,但是我仍然需要了解要做出什麼樣的改變來克服。我的第一個想法是改變WHERE YEAR(l.LogDate)= @年,所以l.LogDate上的索引可以生效。 – Russ

+0

所以看來現在的問題是如何才能讓執行計劃更加優化。我在MS SQL Server Mgmt Studio中關閉了ARITHABORT,並且它仍然運行大約相同的時間。 – Russ

+0

我做了兩個更改,現在它在30秒內運行在Mgmt Studio中。首先,我將WHERE YEAR(l.LogDate)= \ @ Year更改爲WHERE \ @ Jan1 <= l.LogDate AND l.LogDate <= \ @ Dec31。這應該允許利用l.LogDate上的索引。我還在GeocacherPoints.Board上添加了一個索引。不幸的是,儘管在Mgmt Studio下運行時,執行時間大幅下降,但在運行30分鐘後仍然超時。 – Russ

4

如果您正在使用的SqlCommand並沒有爲CommandTimeout指定值時,它會自動在30秒後超時。

+1

OP的意思是30秒......因爲它表示30 *分鐘*。 –

+0

@MichaelPerrenoud:我剛剛意識到,重新閱讀後,問了同樣的問題。 –

+0

太棒了,30秒對我來說也更有意義! –

-1

這個問題似乎週期性地出現,這個鏈接位於列表的頂端: Query times out from web app but runs fine from management studioARITHABORT絕對看起來是罪魁禍首。

+0

'ARITHABORT'不是原因。當'ansi_warnings'不是副作用時,它不起作用,因爲它被用作計劃緩存鍵之一,所以不能共享執行計劃。不同的緩存計劃是實際問題。 –

相關問題