Nit*_*rra 13 sql-server performance stored-procedures function
如果一个语句返回对数据库进行简单选择的行,那么使用Function和Procedures实现它之间是否存在性能差异?我知道最好使用函数来做,但它真的更快?
Rem*_*anu 18
在函数内运行查询和在过程内运行之间的速度没有区别.
存储过程在聚合结果时存在问题,不能与其他存储过程组合.onyl解决方案非常麻烦,因为它涉及将过程输出捕获到表中INSERT ... EXEC ...
,然后使用结果表.
函数具有高度可组合的优点,因为表值函数可以放在预期表表达式的任何位置(FROM,JOIN,APPLY,IN等).但是函数在函数允许的内容和非函数中具有一些非常严格的限制,正是因为它们可以出现在查询中的任何位置.
所以真的是苹果到橘子.决定不是由性能驱动,而是由需求驱动.作为一般规则,返回数据集的任何内容都应该是视图或表值函数.操纵数据的任何东西都必须是一个程序.
A-K*_*A-K 15
有一种流行的误解认为UDF对性能有负面影响.作为一揽子声明,这根本不是真的.事实上,内联表值UDF实际上是宏 - 优化器能够很好地重写涉及它们的查询以及优化它们.但是,标量UDF通常很慢.我将举一个简短的例子.
以下是创建和填充表的脚本:
CREATE TABLE States(Code CHAR(2), [Name] VARCHAR(40), CONSTRAINT PK_States PRIMARY KEY(Code))
GO
INSERT States(Code, [Name]) VALUES('IL', 'Illinois')
INSERT States(Code, [Name]) VALUES('WI', 'Wisconsin')
INSERT States(Code, [Name]) VALUES('IA', 'Iowa')
INSERT States(Code, [Name]) VALUES('IN', 'Indiana')
INSERT States(Code, [Name]) VALUES('MI', 'Michigan')
GO
CREATE TABLE Observations(ID INT NOT NULL, StateCode CHAR(2), CONSTRAINT PK_Observations PRIMARY KEY(ID))
GO
SET NOCOUNT ON
DECLARE @i INT
SET @i=0
WHILE @i<100000 BEGIN
SET @i = @i + 1
INSERT Observations(ID, StateCode)
SELECT @i, CASE WHEN @i % 5 = 0 THEN 'IL'
WHEN @i % 5 = 1 THEN 'IA'
WHEN @i % 5 = 2 THEN 'WI'
WHEN @i % 5 = 3 THEN 'IA'
WHEN @i % 5 = 4 THEN 'MI'
END
END
GO
Run Code Online (Sandbox Code Playgroud)
请考虑以下查询:
SELECT o.ID, s.[name] AS StateName
INTO dbo.ObservationsWithStateNames_Join
FROM dbo.Observations o LEFT OUTER JOIN dbo.States s ON o.StateCode = s.Code
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 1 ms.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'States'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 187 ms, elapsed time = 188 ms.
*/
Run Code Online (Sandbox Code Playgroud)
并将其与涉及内联表值UDF的查询进行比较:
CREATE FUNCTION dbo.GetStateName_Inline(@StateCode CHAR(2))
RETURNS TABLE
AS
RETURN(SELECT [Name] FROM dbo.States WHERE Code = @StateCode);
GO
SELECT ID, (SELECT [name] FROM dbo.GetStateName_Inline(StateCode)) AS StateName
INTO dbo.ObservationsWithStateNames_Inline
FROM dbo.Observations
Run Code Online (Sandbox Code Playgroud)
它的执行计划和执行成本都是相同的 - 优化器已将其重写为外连接.不要低估优化器的强大功能!
这是一个标量UDF:
CREATE FUNCTION dbo.GetStateName(@StateCode CHAR(2))
RETURNS VARCHAR(40)
AS
BEGIN
DECLARE @ret VARCHAR(40)
SET @ret = (SELECT [Name] FROM dbo.States WHERE Code = @StateCode)
RETURN @ret
END
GO
Run Code Online (Sandbox Code Playgroud)
很明显,使用此UDF的查询提供了相同的结果,但它具有不同的执行计划,并且速度显着降低:
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 3 ms.
Table 'Worktable'. Scan count 1, logical reads 202930, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 11890 ms, elapsed time = 38585 ms.
*/
Run Code Online (Sandbox Code Playgroud)
如您所见,优化器可以重写和优化涉及内联表值UDF的查询.另一方面,涉及标量UDF的查询不会被优化器重写 - 最后一个查询的执行包括每行一个函数调用,这非常慢.
归档时间: |
|
查看次数: |
30025 次 |
最近记录: |