查询代码非常慢,但在SSMS中速度很快
我有一个相当简单的查询,我不断地得到超时(它需要三分钟完成,我停止了它,所以我可以发布这个问题),当它在代码中运行,但是当我从同一台计算机运行相同的查询在Sql Server Management Studio中,当数据未在服务器上caching时,查询将仅花费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
什么原因导致了时间差异的主要差异?
为了保持评论部分的清洁,我会在这里回答一些常见问题。
同一台计算机和login用于应用程序和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)
由于数据types优先级的规则,其中@clientID
的types为NVARCHAR(我做了一个信念的飞跃,并假设client_id
列的types为VARCHAR),查询中的Where client_id = @clientID
expression式不是SARG- @clientID
。 因此,应用程序强制执行表扫描,SSMS查询可以快速寻找键。 这是使用Parameters.AddWithValue的一个众所周知和理解的问题,并已在之前的许多文章中讨论过,例如。 请参阅数据访问代码如何影响数据库性能 。 一旦了解问题,解决scheme就变得微不足道:
-
使用接受types的构造函数添加参数:
Parameters.Add("@clientID", SqlDbType.Varchar, 200)
(并传递显式长度以防止caching污染,请参阅未指定参数长度时的查询性能和计划caching问题正确地 -
或在SQL文本
where client_id = cast(@clientID as varchar(200))
参数:where client_id = cast(@clientID as varchar(200))
。
第一个解决scheme是优越的,因为它解决了高速caching污染问题以及SARG能力问题。
我还build议您阅读应用程序中的慢速,SSMS中的快速? 了解性能之谜
在你的c#连接上运行profiler – 可能还有其他的活动,你不知道。
在手动运行查询时从SSMS捕获执行计划,然后在运行应用程序时从Profiler捕获执行计划。 比较和对比。
像这里所build议的那样运行DBCC FREEPROCCACHE
,以确保问题不是由于陈旧的查询执行计划造成的。