Sco*_*ain 17 c# sql sql-server sql-server-2000 .net-4.0
我有一个相当简单的查询,我不断获得超时(它需要超过三分钟完成,我提前停止,所以我可以发布这个问题)在代码运行时,但是当我从同一台计算机运行相同的查询时在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.
}
Run Code Online (Sandbox Code Playgroud)
这是我在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
Run Code Online (Sandbox Code Playgroud)
是什么导致了时间差异的主要差异?
为了保持评论部分的清洁,我将在这里回答一些FAQ.
同一台计算机和登录用于应用程序和ssms.
在我的示例查询中只返回15行.但是,es_history包含11351699 rows和es_history_dt包含8588493 rows.两个表都有很好的索引,SSMS中的执行计划表示他们正在使用索引查找查找,因此它们是快速查找.该程序的行为就好像它没有使用C#版本的查询索引.
Rem*_*anu 31
您在SSMS中的代码与您在应用程序中运行的代码不同.应用程序中的这一行添加了一个NVARCHAR参数:
ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID);
Run Code Online (Sandbox Code Playgroud)
在SSMS脚本中,您将其声明为VARCHAR:
declare @clientID varchar(200)
Run Code Online (Sandbox Code Playgroud)
由于数据类型优先级的规则,Where client_id = @clientID查询中的表达式不具有SARG能力,其中@clientIDNVARCHAR类型(我正在实现信念的飞跃,并假设该client_id列的类型为VARCHAR).因此,应用程序强制进行表扫描,其中SSMS查询可以执行快速键搜索.这是使用Parameters.AddWithValue的一个众所周知的问题,并且在之前的许多文章中已经讨论过,例如.了解数据访问代码如何影响数据库性能.一旦理解了问题,解决方案就是微不足道的:
使用接受类型的构造函数添加参数:( Parameters.Add("@clientID", SqlDbType.Varchar, 200)并确实传递显式长度以防止缓存污染,请参阅查询性能并在未正确指定参数长度时计划缓存问题
或者在SQL文本中转换参数:where client_id = cast(@clientID as varchar(200)).
第一种解决方案是优越的,因为它除了解决SARG能力问题外,还解决了缓存污染问题.
我还建议你在SSMS中快速阅读应用程序,快速阅读?了解性能之谜