我有一个基于SSN查找人的Sql查询并返回PersonID(标识列)。人员表中的SSN列有一个索引。
我有一个旧的VB 6应用程序,它使用COM / .NET互操作来调用此查询。它什么时候运行相对较慢。我使用SQL事件探查器设置跟踪,每个呼叫的持续时间在400毫秒到600毫秒之间。
如果我通过查询分析器运行相同的查询,我会得到一个持续时间< 30毫秒。我还有一个ASP.NET网站,可以进行相同的调用,并且持续时间不到30毫秒。
通常我会怀疑COM / .NET互操作开销会产生延迟。但是我从SQL事件探查器中获取跟踪时间。我无法看到客户端的开销会如何影响我从服务器端数据库跟踪中获得的数字。
还有什么可能导致这个问题?
编辑:
我发现了这个问题。我设置了sql profiler来捕获执行计划,并发现当通过VB应用程序调用存储过程时,执行计划没有使用SSN上的索引。但是,当通过asp.net或QA调用相同的SP时,会调用正确的索引。我发送了一个sp_recompile到服务器,从那时起,VB应用程序以足够的速度运行。
我仍然不明白,为什么VB应用程序没有使用与其他客户端相同的缓存查询计划。
答案 0 :(得分:3)
检查传递给SQL的参数类型(@SSN)。通常会添加如下参数:
List<...> GetBySSN(string ssn) {
SqlCommand cmd = new SqlCommand (@"select ... from ... where SSN=@SSN", conn);
cmd.Parameters.AddWithValue("@SSN", ssn);
using (SqlDataReader rdr = cmd.ExecuteQuery()) {
...
}
}
遗憾的是,此模式将@SSN
参数添加为NVARCHAR
类型(即Unicode)。 SQL Server Data Type Precedence的规则要求将NVARCHAR和VARCHAR之间的比较作为NVARCHAR进行比较,因此执行查询就好像请求了以下SQL一样:
select ... from ... where CAST(SSN as NVARCHAR) = @SSN;
此查询无法从SSN列上的索引中受益,因此将执行表扫描。有90%的时间我调查声明'查询从应用程序运行缓慢但从SSMS运行速度'是这个问题,因为绝大多数开发人员实际上在SSMS中运行不同的查询来与之比较(他们使用VARCHAR参数或硬编码值。)
如果这确实是问题,那么解决方案是微不足道的:明确地将参数类型指定为SqlDbType.VarChar
。