21

我使用 dapper-dot-net 作为 ORM,它会生成以下执行缓慢(1700 毫秒)的 SQL 代码。

exec sp_executesql N'SELECT TOP 5 SensorValue FROM "Values" 
   WHERE DeviceId IN (@id1,@id2) AND SensorId = @sensor 
       AND SensorValue != -32768 AND SensorValue != -32767',N'@id1 
           bigint,@id2 bigint,@sensor int',@id1=139,@id2=726,@sensor=178

当我通过删除参数来修改此代码时,查询的执行速度非常快(20 毫秒)。缺少这些参数是否真的会产生如此大的差异,为什么?

exec sp_executesql N'SELECT TOP 5 SensorValue FROM "Values" 
   WHERE DeviceId IN (139,726) AND SensorId = 178 
       AND SensorValue != -32768 AND SensorValue != -32767'
4

2 回答 2

36

将选项(重新编译)添加到末尾

... AND SensorValue != -32767 OPTION (RECOMPILE) 

我怀疑您正在经历“参数嗅探”

如果是这种情况,我们可以将其保留为 OPTION 或考虑替代方案

更新 1

下面这篇文章将为您介绍“参数嗅探” http://pratchev.blogspot.be/2007/08/parameter-sniffing.html

我建议您了解其中的来龙去脉,因为这将使您更好地理解 sql server 内部结构(可能会咬人)。

如果你理解它,你就会知道如果语句执行得非常频繁,那么与选项重新编译的权衡可能会降低性能。

在我知道根本原因是参数嗅探之后,我个人添加了选项重新编译,除非存在性能问题,否则将其保留。重写语句以避免错误的参数嗅探会导致意图丢失,这会降低可维护性。但是有些情况下重写是合理的(当你这样做时使用好的注释)。

更新 2

我对这个主题的最佳阅读是在第 32 章,名为“参数嗅探:你最好的朋友......除非它不是由 GRANT FRITCHEY 撰写的”

推荐。

SQL Server MVP 深入探讨,第 2 卷

于 2012-06-07T14:01:43.440 回答
9

我最近遇到了同样的问题。我做的第一件事是在 where 语句的列上添加一个非聚集覆盖索引。

这提高了 SQL 的执行时间,但是当 dapper 执行查询时它仍然很慢,实际上它正在超时。

然后我意识到 dapper 生成的查询将参数作为nvarchar(4000) 传递,其中我的 db 表列是 varchar(80) 这导致它执行索引扫描而不是搜索(我建议你阅读索引,如果这对您没有意义。)。意识到这一点后,我将我的 dapper where 语句更新为:

WHERE 参考 = convert(varchar(80),@Reference)

使用上面的 where 语句执行索引查找和 100% 的性能改进。

补充一点:选项(重新编译)对我不起作用。

在所有这些歌曲和舞蹈之后,有一种方法可以告诉 dapper 默认为您执行此操作:

Dapper.SqlMapper.AddTypeMap(typeof(string), System.Data.DbType.AnsiString);

默认情况下,这会将任何字符串参数映射到 varchar(4000) 而不是 nvarchar(4000)。如果您确实需要 Unicode 字符串比较,那么您可以显式地对参数进行转换。

于 2015-07-17T12:48:15.697 回答