查询计划不重复用于相同的查询 sp_executesql vs adhoc

gui*_*e31 5 sql-server optimization execution-plan

我的应用程序中的查询之一是超时。使用 SQL Server 分析器,我能够获得准确的错误 SQL 代码。这是一个sp_executesql动态语句,在服务器上的 SSMS 中运行时间超过 2 分钟。相比之下,临时运行相同的 SQL - 在外面sp_executesql但仍然有参数 - 只需要 600 毫秒。

查看缓存的执行计划,这 2 个查询具有完全相同的查询哈希但不同的计划。我 DBCC FREEPROCCACHEd 准备好的(慢的)希望接下来的执行可以重用临时的快速查询的计划。但事实并非如此。运行 sp_executesql 查询总是重新弹出一个新的、缓慢的计划。

在此处输入图片说明

按照此处的指南,我研究了参数嗅探的可能性。才发现我的4个参数在两个执行计划中完全一样。

在此处输入图片说明

我还尝试OPTION (RECOMPILE)更新相关表的统计信息,但没有结果。

执行计划有 2 个非常相似的主要分支,除了较慢的一个在分支的连接处有嵌套循环,而快速的没有。较低的分支叶子是两个计划中的索引扫描,除了较慢的一个读取数百万行,而较快的一个读取数千行。

在此处输入图片说明 在此处输入图片说明

在较快的索引的使用上没有明显的区别。顶部分支的组织方式略有不同。

准备好的查询可以重用临时缓存的执行计划吗?是什么导致了如此巨大的性能差异?

Eri*_*ing 7

准备好的查询可以重用临时缓存的执行计划吗?

在这种情况下不是,因为DECLARE语句的部分是查询文本的一部分。这与将参数传递给存储过程或动态 SQL 的情况有着根本的不同。

您可能希望阅读本文以更好地理解为什么这些查询不“相同”。

是什么导致了如此巨大的性能差异?

看来您遇到了与此问答相反的问题:

由于该计划最初是使用相同的一组参数编译的,因此重新编译提示不会改变任何内容。您对初始编译的错误猜测会延续到进一步的编译中。

由于您没有以允许任何额外反馈的方式发布查询计划,一些有限的想法可能会有所帮助:

  • 更新此查询中涉及的表/索引的统计信息
  • OPTION(HASH JOIN)向查询添加提示
  • OPTION(OPTIMIZE FOR UNKNOWN)向查询添加提示

在没有完全理解影响的情况下添加查询提示时要谨慎,并且请不要将这些提示添加到其他查询中,希望“它适用于这个查询,因此它也适用于其他任何地方”。