实体框架(4.2)针对SQL Server 2008 R2生成的简单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...
使用目标表上的索引,查询执行速度极快。我还尝试切换用于禁用数据库实例上的参数嗅探(4136)的跟踪标志(http://support.microsoft.com/kb/980653)然而,这似乎没有任何影响。
这给我留下了几个问题:
- 是否要将OPTION(RECOMPILE)查询提示附加到实体框架生成的SQL
- 是否有任何方法可以阻止实体框架使用execsp_executesql,而只是运行原始SQL
- 还有其他人遇到这个问题吗?还有其他提示吗
附加信息:
- 我确实通过SSMS重新启动了数据库实例,但是,我将尝试从服务管理控制台重新启动服务
- 参数化设置为SIMPLE(is_Parameterization_forced:0)
- 针对特定工作负载的优化具有以下设置
- 值:0
- 最小值:0
- 最大值:1
- value_in_use:0
- is_dynamic:1
- is_advanced:1
我还应该提到,如果我在用下面的脚本启用跟踪标志4136之后,通过服务管理控制台重新启动SQL Server服务,似乎实际上清除了跟踪标志。。。也许我应该换一种方式。。。
DBCC TRACEON(4136,-1)
tl;dr
update statistics
我们有一个带有一个参数(主键)的delete
查询,当通过EF和sp_executesql
调用时,该查询大约需要7秒才能完成。手动运行查询,将参数嵌入sp_executesql
的第一个参数中,可以使查询快速运行(约0.2秒)。添加option (recompile)
也起作用。当然,由于我们使用EF,所以这两种解决方案对我们来说是不可用的。
可能是由于级联外键约束,长时间运行的查询的执行计划是,嗯。。。,巨大的当我查看SSMS中的执行计划时,我注意到在某些情况下,不同步骤之间的箭头比其他步骤更宽,这可能表明SQL Server在做出正确的决策时遇到了困难。这让我开始思考统计学。我查看了执行计划中的步骤,以了解可疑步骤中涉及的表格。然后我为那个表运行update statistics Table
。然后我重新运行了错误的查询。我又重新运行了一遍。再说一遍,只是为了确保。它奏效了。我们的表现恢复了正常。(仍然比非sp_executesql
性能差一些,但是嘿!)
事实证明,这只是我们发展环境中的一个问题。(这是一个大问题,因为它使我们的集成测试花费了很长时间。)在我们的生产环境中,我们有一项定期更新所有统计数据的工作。
在这一点上,我建议:
将针对特定工作负载的优化设置设置为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 Server配置管理器使用命令行设置跟踪标志,而不是在查询窗口中使用全局标志。看见http://msdn.microsoft.com/en-us/library/ms187329.aspx