sp_executesql参数很慢

m__*_*m__ 14 sql-server dapper

我使用dapper-dot-net作为ORM,它产生以下,执行缓慢(1700ms)的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
Run Code Online (Sandbox Code Playgroud)

当我通过删除参数来修改此代码时,查询执行速度极快(20ms).缺乏这些参数是否真的会产生这么大的差异?为什么?

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

buc*_*ley 28

添加OPTION(RECOMPILE)到最后

... AND SensorValue != -32767 OPTION (RECOMPILE) 
Run Code Online (Sandbox Code Playgroud)

我怀疑你正在经历"参数嗅探"

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

更新1

以下文章将向您介绍"参数嗅探" http://pratchev.blogspot.be/2007/08/parameter-sniffing.html

我建议你了解ins和out,因为它会让你更好地理解sql server内部(可以咬人).

如果你了解它,你就会知道,用重新编译选项的权衡如果执行的语句是一个性能下降非常频繁.

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

更新2

关于这个主题的最佳读物是在第32章中称为"参数嗅探:你最好的朋友......除非它不是由"GRANT FRITCHEY

这是推荐的.

SQL Server MVP Deep Dives,第2卷

  • “我个人在我的 sql 中保留重新编译选项,除非存在性能问题。” 您的意思是您通常*不*使用选项重新编译,除非存在性能问题?我认为默认情况下始终使用 OPTION RECOMPILE 不是一个好习惯(不要介意建议),除非它会导致问题。 (2认同)

Dev*_*rps 6

我最近遇到了同样的问题.我做的第一件事是在where语句中的列上添加NonClustered Covering Index.

这改善了SQL的执行时间,但是当dapper执行查询时它仍然很慢,实际上它已经超时了.

然后我意识到由dapper生成的查询是作为nvarchar(4000)传递的参数,其中我的db表列是varchar(80)这导致它执行索引扫描而不是搜索(我建议你阅读索引,如果这对你没有意义.)意识到这一点后,我更新了我的小巧玲珑,声明如下:

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

使用上面的where语句执行会导致索引查找,并且性能提高100%.

只是添加:选项(重新编译)对我不起作用.

毕竟这首歌和舞蹈之后,有一种方法可以告诉dapper默认为你做这件事:

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

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