存储过程与函数编译和性能差异
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 的函数。换句话说,现有的执行计划被重用了。与存储过程的行为相同。
【讨论】:
以上是关于存储过程与函数编译和性能差异的主要内容,如果未能解决你的问题,请参考以下文章