[英]Query extremely slow in code but fast in SSMS
我有一個相當簡單的查詢,當它在代碼中運行時,我不斷收到超時(它需要三分鍾以上才能完成,我提前停止了它,所以我可以發布這個問題),但是當我從同一台計算機運行相同的查詢時在 Sql Server Management Studio 中,當數據未緩存在服務器上時,第一次查詢只需要2532 ms
,重復查詢只需要524 ms
。
這是我的 C# 代碼
using (var conn = new SqlConnection("Data Source=backend.example.com;Connect Timeout=5;Initial Catalog=Logs;Persist Security Info=True;User ID=backendAPI;Password=Redacted"))
using (var ada = new SqlDataAdapter(String.Format(@"
SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt
FROM [ES_HISTORY]
inner join [es_history_dt] on [PK_JOB] = [es_historyid]
Where client_id = @clientID and dt > @dt and (job_type > 4 {0}) {1}
Order by dt desc"
, where.ToString(), (cbShowOnlyFailed.Checked ? "and Status = 1" : "")), conn))
{
ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);
ada.SelectCommand.Parameters.AddWithValue("@dt", dtpFilter.Value);
//ada.SelectCommand.CommandTimeout = 60;
conn.Open();
Logs.Clear();
ada.Fill(Logs); //Time out exception for 30 sec limit.
}
這是我在 SSMS 中運行的代碼,我直接從 ada.SelectCommand.CommandText 中提取了它
declare @clientID varchar(200)
set @clientID = '138'
declare @dt datetime
set @dt = '9/19/2011 12:00:00 AM'
SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt
FROM [ES_HISTORY]
inner join [es_history_dt] on [PK_JOB] = [es_historyid]
Where client_id = @clientID and dt > @dt and (job_type > 4 or job_type = 0 or job_type = 1 or job_type = 4 )
Order by dt desc
是什么導致了時間差異的主要差異?
為了保持評論部分的干凈,我將在這里回答一些常見問題解答。
應用程序和 ssms 使用相同的計算機和登錄。
在我的示例查詢中只返回 15 行。 但是, es_history
包含11351699 rows
,而es_history_dt
包含8588493 rows
。 這兩個表都有很好的索引,並且 SSMS 中的執行計划表示它們正在使用索引查找進行查找,因此它們是快速查找。 該程序的行為就好像它沒有使用 C# 版本的查詢的索引。
您在 SSMS 中的代碼與您在應用程序中運行的代碼不同。 應用程序中的這一行添加了一個 NVARCHAR 參數:
ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);
在 SSMS 腳本中,您將其聲明為 VARCHAR:
declare @clientID varchar(200)
由於數據類型優先級的規則,查詢中的Where client_id = @clientID
表達式在@clientID
的類型為 NVARCHAR 的情況下不支持 SARG(我正在做出信念的飛躍,並假設client_id
列的類型為 VARCHAR)。 因此,應用程序強制執行表掃描,SSMS 查詢可以在其中進行快速鍵搜索。 這是使用Parameters.AddWithValue 的一個眾所周知和理解的問題,之前已經在許多文章中討論過,例如。 請參閱數據訪問代碼如何影響數據庫性能。 一旦理解了問題,解決方案就很簡單了:
使用接受類型的構造函數添加參數: Parameters.Add("@clientID", SqlDbType.Varchar, 200)
(並傳遞顯式長度以防止緩存污染,請參閱未指定參數長度時的查詢性能和計划緩存問題正確地
或在 SQL 文本中轉換參數: where client_id = cast(@clientID as varchar(200))
。
第一個解決方案是優越的,因為它除了解決 SARG 能力問題之外,還解決了緩存污染問題。
我還建議您閱讀應用程序中的慢速,SSMS 中的快速? 了解性能奧秘
按照此處的建議運行DBCC FREEPROCCACHE
,以確保問題不是由於過時的查詢執行計划造成的。
有同樣的問題:
解決方案:刪除存儲過程,然后重新創建完全相同的存儲過程,現在都以毫秒為單位返回。 沒有代碼更改。
原因:請有人提出這個修復會產生影響的原因?
在您的 c# 連接上運行探查器 - 可能還有其他您不知道的活動正在進行。
手動運行查詢時從 SSMS 中捕獲執行計划,然后在運行應用程序時從 Profiler 中捕獲執行計划。 比較和對比。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.