在我们的应用程序中,我们有以下数据处理层:
- .NET 编排应用程序,确定要触发的 SSIS 包
- 完成大部分工作并调用存储过程的 SSIS 包
- 在 SSIS 数据流不合适的情况下执行计算和读/写数据的存储过程
如果从 SSMS 执行,一个存储过程将在 40 秒内运行,如果手动调用 SSIS 程序包,则运行时间大致相同。
但是,如果 .NET 应用程序调用 SSIS 包,则查询需要超过 14 小时才能运行,并使所有处理器保持一致。
查看执行计划,似乎如果程序是从 SSMS 运行的,或者手动触发 SSIS 包然后调用该程序,则 SQL Server 使用基于当前统计信息的合理计划。
但是,如果从 .NET 应用程序调用 SSIS 包,则 SQL 服务器会创建一个新计划,使用完全错误的统计信息。以下事情没有区别:
- 更新统计数据
- 清除缓存
- 重启实例
- 在程序执行时设置 WITH RECOMPILE
我们通过在查询中使用 MAXDOP 提示来篡改分辨率,但我的问题是:
当通过我描述的方法使用相同的参数和相同的数据调用时,是什么让 SQL Server 基于完全不正确的统计信息生成完全不同的计划?
看起来您已经在独白中回答了大部分其他问题,并且这些
things that made a difference
是在受到参数嗅探的困扰后强制重新编译的标准清单。要回答您的最后一个问题,请标记为
my question is this
:答案是计划缓存对于在呈现查询的会话上有效的SET 设置非常具体。不同的 SET 设置可能需要非常不同的计划,例如设置
SET ANSI_NULLS
. 您从 SSMS 建立的连接很可能与您的 .Net 应用程序具有不同的设置。这可以通过使用 SQL Server Profiler 跟踪Existing Connections
和来轻松验证Login Audits
,这会向您显示SET
设置。结果是,看似相同的查询将导致一个
Cache Miss
,并且必须创建一个新的查询,这在某种程度上将基于为该查询实例提供给 SQL Server 的参数。