SQL服务器是否会缓存函数的执行计划?

7

有人能帮助我理解SQL Server中缓存函数的执行计划吗?

有没有相关在线资源可以参考?

3个回答

11

被接受的答案存在不准确/误导性,主要是由于引用语句对于术语“用户定义函数”过于模糊。

在Microsoft SQL Server中有几种不同类型的用户定义函数,它们被处理方式不同:

  • 多语句表值函数(Multi-statement TVFs):

    这些函数被视为存储过程。执行它们的查询仅显示对它们名称的引用,而不是任何定义。它们在sys.dm_exec_cached_plans中显示为“Compiled Plan”对象类型和“Proc”缓存对象类型。任何输入参数值也与计划一起存储,因此多语句表值函数存在参数卡顿问题。

  • 内联表值函数(Inline TVFs或iTVFs):

    这些函数被视为视图。执行它们的查询包含了它们的定义。它们在sys.dm_exec_cached_plans中显示为“Parse Tree”对象类型和“View”缓存对象类型。输入参数值与计划一起存储,因此内联表值函数存在参数卡顿问题。

  • 标量UDFs(Scalar UDFs):

    这些函数被视为存储过程。执行它们的查询仅显示对它们名称的引用,而不是任何定义。它们在sys.dm_exec_cached_plans中显示为“Compiled Plan”对象类型和“Proc”缓存对象类型。任何输入参数值也与计划一起存储,因此标量UDFs存在参数卡顿问题。此外,与上述两种表值函数不同但类似于常规存储过程,您可以使用EXEC[UTE]而不是SELECTSET通过WITH RECOMPILE选项强制重新编译执行计划。

  • SQLCLR对象:

    这些对象更像是客户端/应用程序代码。执行它们的查询只显示对它们名称的引用,而不包括它们的定义。它们在sys.dm_exec_cached_plans中以“CLR编译函数”或“CLR编译存储过程”的cacheobjtype和“存储过程”的objtype出现。但是,与多语句表值函数和标量用户定义函数不同的是,它们没有定义,因此也没有相关联的查询计划。然而,它们执行的任何临时查询(非存储过程调用)都会显示在sys.dm_exec_cached_plans中,其cacheobjtype为“Compiled Plan”,objtype为“Prepared”。如果任何这些临时查询有参数化,那么应该将初始输入参数值与预备计划一起存储,并因此受到参数嗅探问题的影响。

  • 有关对象缓存的更多详细信息,请参阅Caching Mechanisms MSDN页面。


    非常感谢您解释每个案例。您知道吗,由于它们被视为视图,是否可以在iTVF上创建索引? - Gabriel Espinoza
    @GabrielEspinoza 不可以在内联表值函数上创建索引,因为它们是内联代码,不定义返回表模式,并且不能在 SELECT 语句中创建索引。将其视为子查询或派生表。对于公共表表达式(CTE)也是如此,因为它们本质上是内联视图。同样,您可以在视图上创建索引,但不能在视图内部创建索引。 - Solomon Rutzky

    8

    是的,它们确实会进入执行计划缓存。

    sys.dm_exec_query_plan DMV将显示给定计划句柄的计划。引用自该处:

    各种类型的Transact-SQL批处理(如临时批处理、存储过程和用户定义的函数)的查询计划被缓存在称为计划缓存的内存区域中。每个缓存的查询计划由唯一标识符(称为计划句柄)标识。您可以使用sys.dm_exec_query_plan动态管理视图指定此计划句柄,以检索特定Transact-SQL查询或批处理的执行计划。


    2

    谢谢,但链接中并没有写明用户定义函数也会被考虑在计划缓存中? - Ashwani K
    2
    这是一篇文章中的引用:“当在SQL Server中执行任何SQL语句时,关系引擎首先查找过程缓存以验证是否存在相同SQL语句的现有执行计划。 SQL Server重用它发现的任何现有计划,节省重新编译SQL语句的开销。 如果不存在现有的执行计划,则SQL Server为查询生成新的执行计划。” - codingbadger

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接