我有一个相当简单的查询,我不断获得超时(完成时间超过三分钟,我提前停止,所以我可以发布此问题),当它在代码中运行时,但是当我运行相同的查询时在Sql Server Management Studio中的同一台计算机上,只有在服务器上没有缓存数据时才会2532 ms
524 ms
,而对于重复查询,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.
}
只会查询{。}}。
这是我的c#代码
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中运行的代码,我从ada.SelectCommand.CommandText
中取出了它es_history
造成时间差异的主要差异是什么?
为了保持评论部分的清洁,我将在这里回答一些常见问题解答。
同一台计算机和登录用于应用程序和ssms。
我的示例查询中只返回了15行。但是,11351699 rows
包含es_history_dt
,8588493 rows
包含{{1}}。两个表都有很好的索引,SSMS中的执行计划表示他们正在使用索引查找查找,因此它们是快速查找。该程序的行为就好像它没有使用查询的C#版本的索引。
答案 0 :(得分:31)
您在SSMS中的代码与您在应用程序中运行的代码不同。应用程序中的这一行添加了一个NVARCHAR参数:
ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);
在SSMS脚本中,您将其声明为VARCHAR:
declare @clientID varchar(200)
由于Data Type Precedence的规则,查询中的Where client_id = @clientID
表达式不具有SARG功能,其中@clientID
的类型为NVARCHAR(我正在实现信仰的飞跃并假设client_id
列的类型为VARCHAR)。因此,应用程序强制进行表扫描,其中SSMS查询可以执行快速键搜索。这是使用Parameters.AddWithValue的一个众所周知的问题,并且在之前的许多文章中已经讨论过,例如。见How Data Access Code Affects Database Performance。一旦理解了问题,解决方案就变得微不足道了:
使用constructor that accepts a type添加参数:Parameters.Add("@clientID", SqlDbType.Varchar, 200)
(以及执行传递显式长度以防止缓存污染,请参阅Query performance and plan cache issues when parameter length not specified correctly
或将参数强制转换为SQL文本:where client_id = cast(@clientID as varchar(200))
。
第一种解决方案是优越的,因为它解决了除SARG能力问题之外的缓存污染问题。
我还建议您阅读Slow in the Application, Fast in SSMS? Understanding Performance Mysteries
答案 1 :(得分:0)
在c#连接上运行探查器 - 可能还有其他您不知道的活动。
答案 2 :(得分:0)
手动运行查询时从SSMS捕获执行计划,然后在运行应用程序时从Profiler捕获执行计划。比较和对比。
答案 3 :(得分:0)
按照建议here运行DBCC FREEPROCCACHE
,以确保问题不是由于陈旧的查询执行计划造成的。