【问题标题】:When to use user defined functions in a SQL Server data warehouse何时在 SQL Server 数据仓库中使用用户定义函数
【发布时间】:2019-01-21 00:55:26
【问题描述】:

我正在创建一个 DWH,我正在将数据加载到 Staging DB 中,在将它们加载到最终 DB 之前,我会应用我在数据上创建的所有 udf。

  • 源数据库:Oracle
  • 目标数据库:SQL Server
  • ETL 过程:SSIS 包

我没有在暂存时处理任何东西来快速加载。

问题:当数据处于暂存状态时应用任何 udf 是否更快,或者是否应该在将数据加载到最终数据库时完成。

facility_cd 下面是一个float 值,我将它传递给函数emr_get_code_Description 以获取相应的描述。从中获取描述的表位于最终数据库中。 udf_replace_special_char 是一个简单的函数,它将一些特殊字符替换为 NULL。

LTRIM(RTRIM([Dest_DWH].[dbo].udf_replace_special_char([Dest_DWH].[dbo].[emr_get_code_Description](Stg_ap.Facility_cd))))

一般来说,更好的做法应该是什么?我是否应该在暂存中更新它,然后在所有转换到最终数据库后加载数据。

函数定义:

功能 1:

USE [PROD_DWH]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER function [dbo].[emr_get_code_Description](@cv int)  
returns varchar(80)  
as begin   

-- Returns the code value display 
    declare @ret varchar(80)  
    select @ret = cv.DESCRIPTION
        from PROD_DWH.DBO.table cv   
        where cv.code_value = @cv   
            and cv.active_ind = 1  

    return isnull(@ret, 0)

end;

功能2:

USE [PROD_DWH]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER function [dbo].[udf_replace_special_char](@var varchar(1000))  
returns varchar(1000)  
as begin   
-- Returns the code value display 
    declare @return_var varchar(1000)  
    set @return_var = @var
    set @return_var = replace(@return_var,CHAR(13),'')
    set @return_var = replace(@return_var,CHAR(10),'')
    set @return_var = replace(@return_var,CHAR(09),'')
    set @return_var = replace(@return_var,CHAR(34),CHAR(39))

    return isnull(@return_var, 0)

end;

【问题讨论】:

  • 我猜从 staging 到 final 但实际上这完全取决于很多变量,我只是测试两者来找出你的答案。
  • 最佳实践是根本不使用 UDF,因为它们有可能引入性能问题。我还要说,最好的做法是在 staging 之前完全准备好数据,然后确保从 staging 到 dw 的负载尽可能快,以减少报告影响。即对事务使用分区切换和/或快照隔离
  • 我完全同意你的看法,尼克。引入一个函数后需要一小时,现在添加第二个函数后需要 2.5 小时。我可以通过替换语句删除 udf_replace_special_char。但另一个函数实际上是包含一个选择语句。我在最初的问题中添加了函数定义。
  • 函数 emr_get_code_Description 在单个表加载中被使用了近 20 次。我在某处读到表值函数提供更好的性能,但在这种情况下,不可能使用它们,因为我需要在存储过程中多次使用该函数。关于如何用其他东西替换这些功能的任何建议都会很棒。 @哈迪
  • @Doodle 正如我在回答中提到的,您可以在主查询中将其替换为 Join

标签: sql sql-server ssis etl data-warehouse


【解决方案1】:

首先,正如@Nick.McDermaid 在 cmets 中提到的:最佳实践是避免使用用户定义的函数。有许多链接包含有关函数对查询性能的影响的信息。


这些问题没有理想的答案,它与您正在处理的案例有关,但我可以提供一些您可以考虑的提示:

  • 首先,如果您使用 SSIS 将数据导入 Staging Table,请尝试使用 SSIS 数据流组件(如派生列转换、查找)替换用户定义的函数,以提高数据导入的性能。
  • 如果您无法用 SSIS 组件替换 UDF:如果您正在将数据高速收集到数据湖(暂存级别),然后在需要时加载数据,则在将数据导入暂存表时最好避免使用函数.
  • 如果您在从 staging 表加载数据时需要保证高速,请在第一个数据导入阶段使用该功能。
  • 如果第一个数据导入阶段(到暂存表)和第二个阶段(从暂存表)不在同一台机器上执行,最好在性能更高的机器上执行功能。
  • 如果函数包含查找等操作,请尝试将其替换为连接。

...

更新 1

在您的问题中发布函数后,您可以将函数 2 替换为 SSIS 包中的派生列转换:

ISNULL([Column]) ? "" : REPLACE(REPLACE(REPLACE(REPLACE([Column],CHAR(10),""),CHAR(13),""),CHAR(09),""),CHAR(34),CHAR(39))

您还可以将函数 1 替换为 SSIS 包中的查找转换或 SQL 查询中的 LEFT JOIN。

【讨论】:

    猜你喜欢
    • 2018-06-30
    • 2018-08-22
    • 2016-11-25
    • 2012-05-16
    • 2015-07-19
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多