Jen*_*Jen 10 sql sql-server-2005 stored-functions
好的,所以我阅读了一大堆文章,建议表值函数和交叉应用提供比标量udf更好的性能.我想以两种方式编写我的函数,然后测试哪一个更好 - 但我无法弄清楚我应该使用/寻找什么是更好的选择.
我正在使用SQL Server 2005.我已经尝试在数据库引擎优化顾问中运行估计的执行计划,实际执行计划和分析查询,我不知道它试图告诉我什么.
使用showplan_all打开/关闭它看起来像基于表的函数将使用更多的CPU 1.157e-06与8.3e-05,但表函数的总子树成本为0.000830157对比0.01983356.
表值函数的查询成本似乎也比标量函数具有更高的成本.即使我认为它应该是更好的选择.
因此,虽然我想自己证明哪一个提供了更好的性能 - 我只是不确定在这些工具中寻找什么 - 所以任何建议都将受到赞赏!
我需要根据日历日期获得学年值(基于数据库中设置的日期范围),因此函数内容低于 - 所以它只是我是基于标量还是基于表.今年提供给其他查询..
CREATE FUNCTION fn_AcademicYear
(
-- Add the parameters for the function here
@StartDate DateTime
)
RETURNS
@AcademicYear TABLE
(
AcademicYear int
)
AS
BEGIN
DECLARE @YearOffset int, @AcademicStartDate DateTime
-- Lookup Academic Year Starting Date
SELECT @AcademicStartDate = CONVERT(DateTime,[Value])
FROM dbo.SystemSetting
WHERE [Key] = 'AcademicYear.StartDate'
SET @YearOffset = DATEPART(YYYY,@StartDate) - DATEPART(YYYY,@AcademicStartDate);
-- try setting academic looking start date to year of the date passed in
SET @AcademicStartDate = DATEADD(YYYY, @YearOffset, @AcademicStartDate);
IF @StartDate < @AcademicStartDate
BEGIN
SET @AcademicStartDate = DATEADD(YYYY, @YearOffset-1, @AcademicStartDate);
END
INSERT @AcademicYear
SELECT YEAR(@AcademicStartDate)
RETURN
Run Code Online (Sandbox Code Playgroud)
谢谢!!
Ed *_*per 17
您可能没有看到预期的性能提升,因为您的表值函数是多功能的,而不是内联的.多功能TVF必须以与标量UDF相同的方式执行 - 每行一次 - 因此获得的收益非常小.
按照Itzik Ben-Gan(讨论在线TVF的好处)本文中的示例,设置以下测试:
创建一个包含100万行的数字表:
SET NOCOUNT ON;
IF OBJECT_ID('dbo.T1') IS NOT NULL DROP TABLE T1;
GO
WITH
L0 AS (SELECT 0 AS c UNION ALL SELECT 0),
L1 AS (SELECT 0 AS c FROM L0 AS A CROSS JOIN L0 AS B),
L2 AS (SELECT 0 AS c FROM L1 AS A CROSS JOIN L1 AS B),
L3 AS (SELECT 0 AS c FROM L2 AS A CROSS JOIN L2 AS B),
L4 AS (SELECT 0 AS c FROM L3 AS A CROSS JOIN L3 AS B),
L5 AS (SELECT 0 AS c FROM L4 AS A CROSS JOIN L4 AS B),
Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS n FROM L5)
SELECT n INTO dbo.T1 FROM Nums WHERE n <= 1000000;
Run Code Online (Sandbox Code Playgroud)
使用以下代码运行一百万次TVF执行:
set statistics time on
SELECT n,DATEADD(HOUR,n,'1900-01-01'),AY.AcademicYear
FROM T1
CROSS APPLY dbo.fn_AcademicYear(DATEADD(HOUR,n,'1900-01-01')) AS AY
set statistics time off
Run Code Online (Sandbox Code Playgroud)
在我的系统上,这表示DBCC dropcleanbuffers在每次执行之间运行三次执行的平均时间为83秒.
如果对标量值函数执行类似的测试,则应该更清楚地了解比较性能.
该测试还揭示了您的功能中似乎存在的错误.如果AcademicYear.StartDate设置为"2010-09-01",则返回"1900-01-01"输入的学年是1789年,预计似乎是1899.
为了获得最佳性能,您需要将TVF转换为内联 - 我想出了以下内容,我相信这可以纠正错误:
CREATE FUNCTION fn_AcademicYear2
(
@StartDate DATETIME
)
RETURNS TABLE
AS
RETURN
(
-- Lookup Academic Year Starting Date
WITH dtCTE
AS
(
SELECT CONVERT(DATETIME,[Value]) AS dt
FROM dbo.SystemSetting
WHERE [KEY] = 'AcademicYear.StartDate'
)
SELECT CASE WHEN @StartDate >= DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate),dt)
THEN YEAR(@StartDate)
ELSE YEAR(DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate) - 1,dt))
END AS AcademicYear
FROM dtCTE
)
GO
Run Code Online (Sandbox Code Playgroud)
在三次运行中平均经过的时间为8.9秒 - 几乎快了十倍.
另一件需要考虑的事情是,使用TVF的性能优势可以忽略不计,除非您将其应用于多行,就像在此测试中一样.如果你一次在一个值上使用它,除非你有数千个并行执行的函数实例,否则你不会看到很多.
| 归档时间: |
|
| 查看次数: |
11108 次 |
| 最近记录: |