调用 TVF 的存储过程怎么会比内联 TVF 的过程慢?

发布于 2024-12-02 10:28:11 字数 3461 浏览 0 评论 0 原文

问题:

我有两个视图:

V_Room, 14969 rows, 9 tables joined together
V_parkings, 3265 rows, 9 tables joined together

然后我有一个视图

V_Rooms_UsageTypes with 18234 rows

,它是 V_Room 和 V_parkings 之间的并集

然后我有一个像这样的表值函数 函数

CREATE FUNCTION [dbo].[tfu_RPT_UsageTypesBySIADetail]
(@in_reporting_date datetime)
-- Add the parameters for the function here
RETURNS TABLE

连接 9 个表的 并在视图 V_Rooms_UsageTypes 上进行如下所示的 77 个子选择

(
        SELECT 
            ISNULL(SUM(ZO_RMArea_Area), 0.0) 
        FROM dbo.V_Rooms_UsageTypes 
        WHERE V_Rooms_UsageTypes.FL_UID = T_Floor.FL_UID 

        AND (V_Rooms_UsageTypes.DIN277_Major = 9) 
        AND (V_Rooms_UsageTypes.DIN277_Minor = 4) 

        AND (V_Rooms_UsageTypes.ZO_RMUT_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.ZO_RMUT_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.ZO_RMArea_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.ZO_RMArea_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.RM_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.RM_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.SO_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.SO_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.BG_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.BG_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.FL_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.FL_DatumTo >= @in_reporting_date) 
    ) AS RPT_VF_9_4 

然后我有一个调用表值函数的存储过程 使用动态 SQL(因为报告服务的多种语言的列别名, 只需要一个一致的列名),

如下所示:

CREATE PROCEDURE [dbo].[sp_RPT_DATA_AreaByDIN277_old]
    @in_customer varchar(3),
    @in_language varchar(2),
    @in_site varchar(36),
    @in_building varchar(36),
    @in_floor varchar(36),
    @in_reporting_date varchar(50)
AS
    DECLARE
    @sql varchar(8000),
    @reporting_date datetime

    -- Abrunden des Eingabedatums auf 00:00:00 Uhr
    SET @reporting_date= CONVERT( DATETIME, @in_reporting_date ) 
    SET @reporting_date= Cast(Floor(Cast(@reporting_date As Float)) As DateTime)
    SET @in_reporting_date= CONVERT(varchar(50), @reporting_date ) 

    SET NOCOUNT ON;



    SET @sql='SELECT  

     FIELD_1_' + @in_language +' AS RPT_FIELD_1
    ,FIELD_2_' + @in_language +' AS RPT_FIELD_2
    ,FIELD_3 AS RPT_FIELD_3 
    ,table_valued_function_column1 AS RPT_table_valued_function_column1
    ,table_valued_function_column2 AS RPT_table_valued_function_column2
    ,table_valued_function_columnN AS RPT_table_valued_function_columnN 

    '



    SET @sql=@sql + 'FROM dbo.tfu_RPT_FM_NutzungsartenNachSIADetail(''' + @in_reporting_date + ''') '

    SET @sql=@sql + 'WHERE ST_Customer = ''' + @in_customer + ''' '


    IF @in_site     <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (ST_UID = ''' + @in_site + ''') '
    IF @in_building <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (BG_UID = ''' + @in_building + ''') '
    IF @in_floor    <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (FL_UID = ''' + @in_floor + ''') '   

    EXECUTE (@sql) 

现在,正如预期的那样,查询需要相当长的时间(20 秒)才能返回结果。 所以我将整个表值函数移到动态sql存储过程中 并且执行速度大约为一半(10 秒)。

相反,我的执行时间为 30 秒。 这是为什么呢?

Question:

I have two views:

V_Room, 14969 rows, 9 tables joined together
V_parkings, 3265 rows, 9 tables joined together

Then I have a view

V_Rooms_UsageTypes with 18234 rows

which is the union between V_Room and V_parkings

Then I have a table valued function like this
Function

CREATE FUNCTION [dbo].[tfu_RPT_UsageTypesBySIADetail]
(@in_reporting_date datetime)
-- Add the parameters for the function here
RETURNS TABLE

Which joins 9 tables
and makes 77 subselects like below onto view V_Rooms_UsageTypes

(
        SELECT 
            ISNULL(SUM(ZO_RMArea_Area), 0.0) 
        FROM dbo.V_Rooms_UsageTypes 
        WHERE V_Rooms_UsageTypes.FL_UID = T_Floor.FL_UID 

        AND (V_Rooms_UsageTypes.DIN277_Major = 9) 
        AND (V_Rooms_UsageTypes.DIN277_Minor = 4) 

        AND (V_Rooms_UsageTypes.ZO_RMUT_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.ZO_RMUT_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.ZO_RMArea_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.ZO_RMArea_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.RM_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.RM_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.SO_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.SO_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.BG_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.BG_DatumTo >= @in_reporting_date) 

        AND (V_Rooms_UsageTypes.FL_DateFrom <= @in_reporting_date) 
        AND (V_Rooms_UsageTypes.FL_DatumTo >= @in_reporting_date) 
    ) AS RPT_VF_9_4 

Then I have a stored procedure which calls the table valued function
using dynamic SQL (because column aliasing for multiple languages for reporting service,
which needs only one consistent column name)

like this:

CREATE PROCEDURE [dbo].[sp_RPT_DATA_AreaByDIN277_old]
    @in_customer varchar(3),
    @in_language varchar(2),
    @in_site varchar(36),
    @in_building varchar(36),
    @in_floor varchar(36),
    @in_reporting_date varchar(50)
AS
    DECLARE
    @sql varchar(8000),
    @reporting_date datetime

    -- Abrunden des Eingabedatums auf 00:00:00 Uhr
    SET @reporting_date= CONVERT( DATETIME, @in_reporting_date ) 
    SET @reporting_date= Cast(Floor(Cast(@reporting_date As Float)) As DateTime)
    SET @in_reporting_date= CONVERT(varchar(50), @reporting_date ) 

    SET NOCOUNT ON;



    SET @sql='SELECT  

     FIELD_1_' + @in_language +' AS RPT_FIELD_1
    ,FIELD_2_' + @in_language +' AS RPT_FIELD_2
    ,FIELD_3 AS RPT_FIELD_3 
    ,table_valued_function_column1 AS RPT_table_valued_function_column1
    ,table_valued_function_column2 AS RPT_table_valued_function_column2
    ,table_valued_function_columnN AS RPT_table_valued_function_columnN 

    '



    SET @sql=@sql + 'FROM dbo.tfu_RPT_FM_NutzungsartenNachSIADetail(''' + @in_reporting_date + ''') '

    SET @sql=@sql + 'WHERE ST_Customer = ''' + @in_customer + ''' '


    IF @in_site     <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (ST_UID = ''' + @in_site + ''') '
    IF @in_building <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (BG_UID = ''' + @in_building + ''') '
    IF @in_floor    <> '00000000-0000-0000-0000-000000000000' SET @sql=@sql + 'AND (FL_UID = ''' + @in_floor + ''') '   

    EXECUTE (@sql) 

Now, expectedly, this took a rather long time (20s) for the query to return the results.
So I moved the entire table valued function into the dynamic sql stored procedure
and excepted to have an execution speed of roughly half (10s).

Instead, I got an execution time of 30s.
Why is this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我不是你的备胎 2024-12-09 10:28:11

与单独优化 TVF 相比,引擎很可能能够更好地处理它,而 TVF 只是更大查询的一部分。此外,动态 SQL 可能会改变计划的缓存方式。您忘记提及您正在使用的 SQL Server 版本,但是您是否使用过“优化临时工作负载"设置,或优化未知

It's quite possible that the engine can better deal with optimizing the TVF separately than when it's just part of a much larger query. Also the dynamic SQL may change the way the plans are cached. You forgot to mention which version of SQL Server you're using, but have you played with the "optimize for ad hoc workloads" setting, or OPTIMIZE FOR UNKNOWN??

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文