Entity Framework 4.2 exec sp_executesql不使用索引(参数嗅探)
我遇到了由对SQL Server 2008 R2运行的entity framework(4.2)生成的简单SQL查询的一些主要性能问题。 在某些情况下(但不是全部),EF使用以下语法:
exec sp_executesql 'DYNAMIC-SQL-QUERY-HERE', @param1...
在其他情况下,只需执行提供的参数烘焙到查询中的原始SQL。 我遇到的问题是,使用sp_executesql执行的查询忽略了目标表上的所有索引,导致性能极差(通过检查SSMS中的执行计划进行确认)。
经过一番研究,听起来这个问题可能是由“参数嗅探”造成的。 如果我追加OPTION(RECOMPILE)查询提示像这样:
exec sp_executesql 'DYNAMIC-SQL-QUERY-HERE OPTION(RECOMPILE)', @param1...
使用目标表上的索引,查询执行速度非常快。 我也尝试切换用于禁用数据库实例( http://support.microsoft.com/kb/980653 )上的参数嗅探(4136)的跟踪标志,但是这看起来没有任何效果。
这给我留下了几个问题:
- 有没有办法将OPTION(RECOMPILE)查询提示附加到Entity Framework生成的SQL?
- 无论如何阻止Entity Framework使用exec sp_executesql,而只是运行原始SQL?
- 有没有人遇到这个问题? 任何其他提示/提示?
附加信息:
- 我没有通过SSMS重新启动数据库实例,但是,我将尝试从服务pipe理控制台重新启动服务。
- 参数化设置为SIMPLE(is_parameterization_forced:0)
- 优化特别工作负载有以下设置
- 值:0
- 最小值:0
- 最大:1
- value_in_use:0
- is_dynamic:1
- is_advanced:1
我还应该提到,如果我通过服务pipe理控制台在使用下面的脚本启用跟踪标志4136后重新启动SQL Server服务,似乎实际上清除跟踪标志…也许我应该这样做一个不同的方式…
DBCC TRACEON(4136,-1)
在这一点上,我会build议:
将ad hoc工作负载的优化设置为true。
EXEC sp_configure 'show advanced', 1; GO RECONFIGURE WITH OVERRIDE; GO EXEC sp_configure 'optimize for ad hoc', 1; GO RECONFIGURE WITH OVERRIDE GO EXEC sp_configure 'show advanced', 0; GO RECONFIGURE WITH OVERRIDE; GO
如果一段时间后这个设置似乎没有帮助,只有这样我才能尝试追踪标志的额外支持。 这些通常是保留作为最后的手段。 通过SQL Serverconfigurationpipe理器使用命令行来设置跟踪标志,而不是在查询窗口中使用全局标志。 请参阅http://msdn.microsoft.com/en-us/library/ms187329.aspx
TL;博士
update statistics
我们使用一个参数(主键)进行delete
查询,当通过EF和sp_executesql
调用时,需要大约7秒才能完成。 手动运行查询,将参数embeddedsp_executesql
的第一个参数中,使查询快速运行(约0.2秒)。 添加option (recompile)
也工作。 当然,自从使用EF以来,这两种解决方法并不适用于我们。
可能是由于级联外键约束,长时间运行的查询的执行计划是,呃…,巨大的。 当我看到SSMS中的执行计划时,我注意到在某些情况下,不同步骤之间的箭头比其他步骤更宽,可能表明SQL Server难以做出正确的决定。 这导致我想到统计。 我查看了执行计划中的步骤,以查看可疑步骤涉及的表格。 然后我运行该表的update statistics Table
。 然后我重新运行错误的查询。 我又重新跑了一遍。 再一次只是为了确定。 有效。 我们的performance恢复了正常。 (仍然比非sp_executesql
性能差一些,但嘿!)
原来这只是我们开发环境中的一个问题。 (这是一个很大的问题,因为它使得我们的集成testing一直持续下去。)在我们的生产环境中,我们有一个工作正在运行,定期更新所有的统计数据。