【问题标题】: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 是内联的,例如:-)。

标签: sql-server stored-procedures


【解决方案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 与动态(非参数)查询混合在一起。如果有人找到支持该论点的轻微信息,请报告。

【讨论】:

【解决方案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 的函数。换句话说,现有的执行计划被重用了。与存储过程的行为相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 2023-03-15
    • 2012-02-11
    • 1970-01-01
    • 2020-04-19
    相关资源
    最近更新 更多