存储过程与函数编译和性能差异

Posted

技术标签:

【中文标题】存储过程与函数编译和性能差异【英文标题】:Stored Procedure vs Functions compilation and performance difference 【发布时间】:2013-12-10 13:31:55 【问题描述】:

最近我做了一个 inetrview,面试官让我解释一下存储过程和 UDF 之间最基本的区别。

我能够回忆起 listed here 的一些差异,但他不接受其中任何一个作为 BASIC 差异。

他的回答是 SP 只编译一次,而 UDF 每次调用时都会编译,导致 UDF 比存储过程慢得多。

现在我已经搜索但无法得到明确的答案,这个断言是否正确。 请验证这一点。

【问题讨论】:

我知道 UDF 的估计行数一直是 1... 他们错了。每次调用 UDF 时都不会重新编译它们。这可以通过多种方式来证明。例如在分析器中跟踪(重新)编译事件,查看缓存 DMV 的计划。 My answer here 在多次执行 UDF 时查看堆栈跟踪。开销是在执行期间而不是编译期间。 什么样的函数 - 标量或内联表值或多语句表值?这三种是具有不同执行机制的不同类型的对象(内联 TVF 是内联的,例如:-)。 【参考方案1】:

@mhasan,感谢您在问题中引用我的博文。

据我所知,存储过程函数在编译和重新编译方面都具有相同的行为。两者都未预编译。当您创建其中任何一个时,它们只是被解析和创建,而不是编译。两者都是在第一次执行时编译的。如果对它们应用了任何更改,它们可以再次自动重新编译。

创建新函数后执行以下查询:

SELECT objtype, cacheobjtype, usecounts, text 
FROM   sys.dm_exec_cached_plans AS p
       CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
WHERE  t.text LIKE '%YourNewFunctionName%' 

您只会看到一条记录,即此查询本身的已编译计划,即 Adhoc Object-Type。

执行函数 rre 后再次执行此查询。你会看到更多的记录,包括函数的Compiled计划,它的Object-Type为Proc。

希望这会有所帮助。

【讨论】:

感谢 manaoj bhai.. 我已为您的博客添加了书签...将从那里学到很多东西。【参考方案2】:

这是一个奇怪的说法,据我所知,UDF 和 SP 的编译(并在它更改时重新编译)是一样的。您的面试官似乎将 UDF 与动态(非参数)查询混合在一起。如果有人找到支持该论点的轻微信息,请报告。

【讨论】:

补充一点,是的,Scalar UDF 可能很慢,关于它的一个很好的讲座是这篇文章和随后的讨论。 sqlservercentral.com/articles/T-SQL/91724【参考方案3】:

Jean 是对的,它们肯定只编译过一次。

以下查询将为您提供过程缓存并包括有用的指标,例如执行计数、读取等:

SELECT TOP 1000 DB_NAME(qt.dbid)                                         AS DB,
                OBJECT_NAME(qt.objectid, qt.dbid)                        AS 'object_name',
                qs.total_worker_time,
                qs.execution_count,
                qs.total_logical_reads,
                plan_generation_num,
                SUBSTRING(qt.text, ( qs.statement_start_offset / 2 ) + 1, 
                                    ( ( CASE statement_end_offset
                                            WHEN -1 THEN DATALENGTH(qt.text)
                                            ELSE qs.statement_end_offset
                                            END - qs.statement_start_offset ) / 2 ) + 1) AS 'query'
FROM   sys.dm_exec_query_stats AS qs
       CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
       LEFT JOIN sys.objects o
         ON o.object_id = qt.objectid
WHERE  qs.execution_count > 0
       AND DATEDIFF(Second, qs.creation_time, GETDATE()) > 0
       AND DATEDIFF(Minute, qs.creation_time, GETDATE()) > 0
ORDER  BY /*Sort functions first*/
          CASE
            WHEN o.type_desc LIKE '%FUNCTION' THEN 0
            ELSE 1
          END,
          qs.execution_count DESC 

在报告中,我可以看到执行计数高于 1 的函数。换句话说,现有的执行计划被重用了。与存储过程的行为相同。

【讨论】:

以上是关于存储过程与函数编译和性能差异的主要内容,如果未能解决你的问题,请参考以下文章

存储过程 - 函数性能差异

视图和存储过程之间是不是存在性能差异

存储过程与SQL语句怎么选择

循环与调用函数的 SQL 性能差异

Sqlserver中存储过程,触发器,自定义函数

MySQL存储过程