在我的表视图中,我有4个要调用的标量函数。 例如:
CREATE view [SUMMARY]
AS
SELECT [Code] ,
...
dbo.[udf_REPORTTYPE](ts.LegTankSystemId,ReportingDate,analysis.[AnalysisTypeName]) as ReportingType ,
dbo.[udf_WATER](ts.SystemId,LastObsDate) as WaterReading,
case when analysis.LastObsDate is null then NULL else dbo.[udf_BJs_GENERAL](ts.LegTankSystemId,ISNULL(analysis.LastObsDate, ssd.ReportingDate)) end as [1Plus130_Reslut],
(CASE WHEN State ='NY' THEN dbo.[udf_NY](ts.SystemId,LastObsDate)
WHEN State ='CT' THEN dbo.[udf_CT] (ts.SystemId,LastObsDate)
END) AS State_SIR_Result
FROM LOBDW.SITE dimsite
LEFT JOIN [bjs].[udv_TANK] ts on dimsite.SiteId = ts.SiteId
...
在那些标量函数中,我读取相同的参数并进行不同的计算。
返回400行我的视图需要1分钟以上。真的很糟糕。 如何提高这些标量函数的性能?有没有办法从一个函数定义全局变量,如果两个函数都需要相同的数据,那么在另一个函数中使用它?
例如功能;
CREATE FUNCTION [dbo].[udf_REPORTTYPE]
(
@TankSystemId int,
@TimeStamp datetime2(7),
@AnalysisTypeName varchar(10)
)
RETURNS varchar(10)
AS
BEGIN
DECLARE @ReportType varchar(10);
DECLARE @TimePeriod datetime2(7)
DECLARE @LatestAnalysisDate datetime2(7)
SELECT TOP 1 @TimePeriod = Date FROM udv_DailySiraData where TankSystemId=@TankSystemId ORDER BY Date DESC
SELECT TOP 1 @LatestAnalysisDate = LastObsDate FROM [udv_ANALYSES] where TankSystemId =@TankSystemId ORDER BY LastObsDate DESC
SET @ReportType=@AnalysisTypeName
IF ((@TimePeriod>=@TimeStamp) AND (@LatestAnalysisDate < @TimeStamp) AND @AnalysisTypeName IS NULL)
SET @ReportType = 'No Analysis Result';
IF ((@TimePeriod>=@TimeStamp) AND @AnalysisTypeName IS NULL)
SET @ReportType = 'Latest';
RETURN @ReportType;
END;
答案 0 :(得分:3)
您可以将UDF转换为OUTER APPLY,类似这样
SELECT [Code] ,
...
--dbo.[udf_REPORTTYPE](ts.LegTankSystemId,ReportingDate,analysis.[AnalysisTypeName]) as ReportingType , -- change from UDF to Outer Apply
RT.ReportingType,
dbo.[udf_WATER](ts.SystemId,LastObsDate) as WaterReading,
case when analysis.LastObsDate is null then NULL else dbo.[udf_BJs_GENERAL](ts.LegTankSystemId,ISNULL(analysis.LastObsDate, ssd.ReportingDate)) end as [1Plus130_Reslut],
(CASE WHEN State ='NY' THEN dbo.[udf_NY](ts.SystemId,LastObsDate)
WHEN State ='CT' THEN dbo.[udf_CT] (ts.SystemId,LastObsDate)
END) AS State_SIR_Result
FROM LOBDW.SITE dimsite
LEFT JOIN [bjs].[udv_TANK] ts on dimsite.SiteId = ts.SiteId
OUTER APPLY -- convert from udf_REPORTTYPE
(
SELECT ReportingType =
CASE WHEN MAX(x.DATE) >= ssd.ReportingDate
AND MAX(y.LastObsDate) < ssd.ReportingDate
AND analysis.[AnalysisTypeName] iS NULL
THEN 'No Analysis Result'
WHEN MAX(x.DATE) >= ssd.ReportingDate
AND analysis.[AnalysisTypeName] iS NULL
THEN 'Latest'
ELSE analysis.[AnalysisTypeName]
END
FROM udv_DailySiraData x
INNER JOIN udv_ANALYSES y ON x.TankSystemId = y.TankSystemId
WHERE x.TankSystemId = ts.LegTankSystemId
) RT
答案 1 :(得分:1)
这里是外部申请的CTE替代方案,虽然我确信它运作得很好......
WITH TimePeriods AS (
SELECT
TankSystemId,
TimePeriod = MAX(Date)
FROM
udv_DailySiraData
GROUP BY
TankSystemId
), AnalysisDates AS (
SELECT
TankSystemId,
LatestAnalysisDate = MAX(LastObsDate)
FROM
udv_ANALYSES
GROUP BY
TankSystemId
)
SELECT
...
ReportingType =
CASE
WHEN tp.TimePeriod >= ReportingDate AND ad.LatestAnalysisDate < ReportingDate AND analysis.AnalysisTypeName IS NULL THEN 'No Analysis Result'
WHEN tp.TimePeriod >= ReportingDate AND analysis.AnalysisTypeName IS NULL THEN 'Latest'
ELSE analysis.AnalysisTypeName
END,
...
FROM
LOBDW.SITE dimsite
LEFT JOIN
bjs.udv_TANK ts
ON dimsite.SiteId = ts.SiteId
LEFT JOIN
TimePeriods tp
ON ts.LegTankSystemId = tp.TankSystemId
LEFT JOIN
AnalysisDates ad
ON ts.LegTankSystemId = tp.TankSystemId