存在函数时的 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,因为它(很可能,参考我的第一个假设)不需要。