何时在 SQL 服务器数据仓库中使用用户定义的函数
When to use user defined functions in a SQL Server data warehouse
我正在创建一个 DWH,我在其中将数据加载到暂存数据库中,在将它们加载到最终数据库之前,我应用了我在数据上创建的所有 udf。
- 源数据库:甲骨文
- 目标数据库:SQL服务器
- ETL 过程:SSIS 包
我没有在暂存中处理任何内容以快速加载。
问题:当数据本身处于暂存状态时应用任何 udf 是否更快,还是应该在将数据加载到最终数据库时应用任何 udf 更快。
下面facility_cd
是一个float
值,我将它传递给一个函数emr_get_code_Description
以获得相应的描述。从中获取描述的 table 在最终数据库中。 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;
首先,正如评论中提到的@Nick.McDermaid:最佳做法是避免使用用户定义的函数。有许多链接包含有关函数对查询性能影响的信息。
- Removing Function Calls for Better Performance in SQL Server
- Performance Considerations of User-Defined Functions in SQL Server 2012
- Are SQL Server Functions Dragging Your Query Down?
- T-SQL Best Practices - Don't Use Scalar Value Functions in Column List or WHERE Clauses
这些问题没有理想的答案,这与您正在处理的案例有关,但我可以提供一些您可以考虑的提示:
- 首先,如果您使用 SSIS 将数据导入 Staging Table,请尝试用派生列转换、查找等 SSIS 数据流组件替换用户定义的函数,以提高性能数据导入。
- 如果您不能用SSIS组件替换UDF:如果您正在高速收集数据到数据湖(暂存级别),然后在需要时加载数据,最好避免在导入数据时使用函数分期 table.
- 如果你需要保证从staging加载数据时的高速table,那么使用第一个数据导入阶段的功能。
- 如果第一个数据导入阶段(到暂存table)和第二个阶段(从暂存table)不在同一台机器上执行,最好在性能更高的机器。
- 如果函数包含查找等操作,请尝试用联接替换它们。
...
更新 1
在您的问题中发布函数后,您可以在 SSIS 包中用派生列转换替换函数 2:
ISNULL([Column]) ? "" : REPLACE(REPLACE(REPLACE(REPLACE([Column],CHAR(10),""),CHAR(13),""),CHAR(09),""),CHAR(34),CHAR(39))
您还可以用 SSIS 包中的查找转换或 SQL 查询中的 LEFT JOIN 替换函数 1。
我正在创建一个 DWH,我在其中将数据加载到暂存数据库中,在将它们加载到最终数据库之前,我应用了我在数据上创建的所有 udf。
- 源数据库:甲骨文
- 目标数据库:SQL服务器
- ETL 过程:SSIS 包
我没有在暂存中处理任何内容以快速加载。
问题:当数据本身处于暂存状态时应用任何 udf 是否更快,还是应该在将数据加载到最终数据库时应用任何 udf 更快。
下面facility_cd
是一个float
值,我将它传递给一个函数emr_get_code_Description
以获得相应的描述。从中获取描述的 table 在最终数据库中。 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;
首先,正如评论中提到的@Nick.McDermaid:最佳做法是避免使用用户定义的函数。有许多链接包含有关函数对查询性能影响的信息。
- Removing Function Calls for Better Performance in SQL Server
- Performance Considerations of User-Defined Functions in SQL Server 2012
- Are SQL Server Functions Dragging Your Query Down?
- T-SQL Best Practices - Don't Use Scalar Value Functions in Column List or WHERE Clauses
这些问题没有理想的答案,这与您正在处理的案例有关,但我可以提供一些您可以考虑的提示:
- 首先,如果您使用 SSIS 将数据导入 Staging Table,请尝试用派生列转换、查找等 SSIS 数据流组件替换用户定义的函数,以提高性能数据导入。
- 如果您不能用SSIS组件替换UDF:如果您正在高速收集数据到数据湖(暂存级别),然后在需要时加载数据,最好避免在导入数据时使用函数分期 table.
- 如果你需要保证从staging加载数据时的高速table,那么使用第一个数据导入阶段的功能。
- 如果第一个数据导入阶段(到暂存table)和第二个阶段(从暂存table)不在同一台机器上执行,最好在性能更高的机器。
- 如果函数包含查找等操作,请尝试用联接替换它们。
...
更新 1
在您的问题中发布函数后,您可以在 SSIS 包中用派生列转换替换函数 2:
ISNULL([Column]) ? "" : REPLACE(REPLACE(REPLACE(REPLACE([Column],CHAR(10),""),CHAR(13),""),CHAR(09),""),CHAR(34),CHAR(39))
您还可以用 SSIS 包中的查找转换或 SQL 查询中的 LEFT JOIN 替换函数 1。