存在函数时的 TSQL 视图 select 优化
TSQL view select optimization when function is present
我将这个简单的 SQL 作为 SSIS 任务的来源:
Select * from budgetview
来源是:
CREATE VIEW [dbo].[BudgetView] AS
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
dbo.fn_DateFromJulian(SDIVD) AS Date,
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460
没有关于索引的建议,一切似乎都经过了优化。
函数fn_DateFromJulian
来源是:
CREATE FUNCTION [dbo].[fn_DateFromJulian]
(
@JulianDate numeric(6,0)
)
RETURNS date
AS
BEGIN
declare @resultdate date=dateadd(year,@JulianDate/1000,'1900-01-01')
set @resultdate=dateadd(day,@JulianDate%1000 -1,@resultdate)
return @resultdate
END
问题是我等了大约 20 分钟才让行进入 SSIS....
我在那里等了 20 分钟才开始
有没有找到罪魁祸首的建议?
我的假设是花在视图上的时间是通过计算 Julian 日期值消耗的。在没有看到实际查询计划的情况下,根据下面的文章,这似乎是一个合理的猜测。
将原始函数重写为下面的 table 值函数(我只是将您的代码混合在一起,可能有改进的机会)
CREATE FUNCTION dbo.fn_DateFromJulianTVF
(
@JulianDate numeric(6,0)
)
RETURNS TABLE AS
RETURN
(
SELECT dateadd(day,@JulianDate%1000 -1,dateadd(year,@JulianDate/1000,CAST('1900-01-01' AS date))) AS JDEDate
)
用法是
CREATE VIEW [dbo].[BudgetView] AS
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
J.JDEDate AS [Date],
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460 AS T
CROSS APPLY
dbo.fn_DateFromJulianTVF(T.SDIVD) AS J
标量值函数,闻起来像代码重用,性能像重复使用的一次性尿布
只是检查一下,但我是否理解 T.SDIVD
的每个唯一值都将只有一个唯一的函数结果值?换句话说,没有两个不同的T.SDIVD
会return从函数中得到相同的值吗?
在这种情况下,这里发生的事情(恕我直言)是您首先扫描整个 table,为每条记录计算 f(SDIVD) 值,然后通过一个聚合(不同)。
由于函数在 MSSQL 中远非最佳,我建议通过扭转事件链并像这样来限制它们的使用:
CREATE VIEW [dbo].[BudgetView] AS
SELECT /* DISTINCT */
Country,
Company,
Customer,
PrintableItemNumber,
dbo.fn_DateFromJulian(SDIVD) AS Date,
Quantity,
Value,
Weight
FROM (
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
SDIVD,
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460 ) dist_F553460
)
如果您有很多双重记录,这应该会提高性能,如果您只有很少的双重记录,则不会产生太大影响(如果有的话)。如果你知道你根本没有双打,你应该首先摆脱 DISTINCT
因为这是导致延迟的原因!
无论如何,关于功能你可以添加以下技巧:
CREATE FUNCTION [dbo].[fn_DateFromJulian]
(
@JulianDate numeric(6,0)
)
RETURNS date
WITH SCHEMABINDING
AS
BEGIN
declare @resultdate date=dateadd(year,@JulianDate/1000,'1900-01-01')
set @resultdate=dateadd(day,@JulianDate%1000 -1,@resultdate)
return @resultdate
END
WITH SCHEMABINDING
会进行一些内部优化,使其执行速度稍快一些,YMMV。它有一些局限性,但在这里它会很好地工作。
编辑:删除了 'outer' DISTINCT,因为它(很可能,参考我的第一个假设)不需要。
我将这个简单的 SQL 作为 SSIS 任务的来源:
Select * from budgetview
来源是:
CREATE VIEW [dbo].[BudgetView] AS
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
dbo.fn_DateFromJulian(SDIVD) AS Date,
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460
没有关于索引的建议,一切似乎都经过了优化。
函数fn_DateFromJulian
来源是:
CREATE FUNCTION [dbo].[fn_DateFromJulian]
(
@JulianDate numeric(6,0)
)
RETURNS date
AS
BEGIN
declare @resultdate date=dateadd(year,@JulianDate/1000,'1900-01-01')
set @resultdate=dateadd(day,@JulianDate%1000 -1,@resultdate)
return @resultdate
END
问题是我等了大约 20 分钟才让行进入 SSIS....
我在那里等了 20 分钟才开始
有没有找到罪魁祸首的建议?
我的假设是花在视图上的时间是通过计算 Julian 日期值消耗的。在没有看到实际查询计划的情况下,根据下面的文章,这似乎是一个合理的猜测。
将原始函数重写为下面的 table 值函数(我只是将您的代码混合在一起,可能有改进的机会)
CREATE FUNCTION dbo.fn_DateFromJulianTVF
(
@JulianDate numeric(6,0)
)
RETURNS TABLE AS
RETURN
(
SELECT dateadd(day,@JulianDate%1000 -1,dateadd(year,@JulianDate/1000,CAST('1900-01-01' AS date))) AS JDEDate
)
用法是
CREATE VIEW [dbo].[BudgetView] AS
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
J.JDEDate AS [Date],
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460 AS T
CROSS APPLY
dbo.fn_DateFromJulianTVF(T.SDIVD) AS J
标量值函数,闻起来像代码重用,性能像重复使用的一次性尿布
只是检查一下,但我是否理解 T.SDIVD
的每个唯一值都将只有一个唯一的函数结果值?换句话说,没有两个不同的T.SDIVD
会return从函数中得到相同的值吗?
在这种情况下,这里发生的事情(恕我直言)是您首先扫描整个 table,为每条记录计算 f(SDIVD) 值,然后通过一个聚合(不同)。
由于函数在 MSSQL 中远非最佳,我建议通过扭转事件链并像这样来限制它们的使用:
CREATE VIEW [dbo].[BudgetView] AS
SELECT /* DISTINCT */
Country,
Company,
Customer,
PrintableItemNumber,
dbo.fn_DateFromJulian(SDIVD) AS Date,
Quantity,
Value,
Weight
FROM (
SELECT DISTINCT Country,
SDCO AS Company,
SDAN8 AS Customer,
SDLITM AS PrintableItemNumber,
SDIVD,
SDPQOR/100.0 AS Quantity,
SDAEXP/100.0 AS Value,
SDITWT/10000.0 AS Weight
FROM dbo.F553460 ) dist_F553460
)
如果您有很多双重记录,这应该会提高性能,如果您只有很少的双重记录,则不会产生太大影响(如果有的话)。如果你知道你根本没有双打,你应该首先摆脱 DISTINCT
因为这是导致延迟的原因!
无论如何,关于功能你可以添加以下技巧:
CREATE FUNCTION [dbo].[fn_DateFromJulian]
(
@JulianDate numeric(6,0)
)
RETURNS date
WITH SCHEMABINDING
AS
BEGIN
declare @resultdate date=dateadd(year,@JulianDate/1000,'1900-01-01')
set @resultdate=dateadd(day,@JulianDate%1000 -1,@resultdate)
return @resultdate
END
WITH SCHEMABINDING
会进行一些内部优化,使其执行速度稍快一些,YMMV。它有一些局限性,但在这里它会很好地工作。
编辑:删除了 'outer' DISTINCT,因为它(很可能,参考我的第一个假设)不需要。