我有一个内联表值函数,由于某种原因它运行速度非常慢,我只需要取消它。
当我在临时的基础上运行相同的确切SQL,并通过声明和设置它们来创建参数时,它会按预期在大约3分钟内运行。如何简单地将其作为ITVF与ad hoc运行是如何创造性能差异的?!
我最近发现的一个额外的皱纹是,如果我将它作为ITVF运行,并将其传递x
值,它会在大约3分钟内运行,当我传递它y
值时,它需要永远。当我特别运行它时,我正在使用所谓的麻烦的y
值,它在3分钟内运行!我不希望这会对主要问题造成太大影响,即SQL如何在ITVF上运行得更快,我只想提及它以防它提供一些见解。
这是ITVF签名:
[aop].[itvfOpsProductivity](@Interval varchar(7),@ToMonth tinyint = 12,@AOPYear char(4),@PLANNING_EstimateType varchar(4),@ACTYear char(4))
以下是我打电话给ITVF的方式
select * from [aop].[itvfOpsProductivity]('YTD',10,'2017','AOP','2016')
当我在第3个参数中使用'2016'而不是'2017'调用ITVF时,它运行良好。
以下是我如何运行SQL内联/ ad hoc(它运行良好):
declare @Interval varchar(7)
set @Interval='YTD'
declare @ToMonth tinyint
set @ToMonth=10
declare @AOPYear char(4)
set @AOPYear='2017'
declare @PLANNING_EstimateType varchar(4)
set @PLANNING_EstimateType='AOP'
declare @ACTYear char(4)
set @ACTYear='2016'
SELECT
Financial.Segment,
Financial.EstimateRegionName as Region,
Financial.EstimateClusterName as Cluster,
Financial.EstimateCountryName as Country,
Financial.SAPCountryCode,
Operational.BU,
Operational.[Equipment Class],
Operational.ProductGroupCode,
Operational.ProductGroupCodeDesc,
Operational.ServiceCode,
Operational.ServiceCodeDesc,
Operational.[TEU or Install_ACT],
Operational.[TEU or Install_AOP],
Operational.[Hours_ACT],
Operational.[Hours_AOP],
Operational.[OriginalHours_AOP],
Operational.[Part Cost_ACT],
Operational.[Part Cost_AOP],
Operational.[OriginalPart Cost_AOP],
IsNull(Operational.TotalHoursPerCountry_ACT,0) as TotalHoursPerCountry_ACT,
IsNull(Operational.TotalHoursPerCountry_AOP,0) as TotalHoursPerCountry_AOP,
Case When Operational.TotalHoursPerCountry_ACT<>0
Then ( IsNull(Financial.TotalCostPerCountry_ACT,0) - Operational.FEPartCostPerCountry_ACT ) / Operational.TotalHoursPerCountry_ACT
End as FullyBurdenedBHR_ACT,
Case When Operational.TotalHoursPerCountry_AOP<>0
Then ( IsNull(Financial.TotalCostPerCountry_AOP,0) - Operational.FEPartCostPerCountry_AOP ) / Operational.TotalHoursPerCountry_AOP
End as FullyBurdenedBHR_AOP,
Operational.FEPartCostPerCountry_ACT,
Operational.FEPartCostPerCountry_AOP,
Financial.TotalCostPerCountry_ACT,
Financial.TotalCostPerCountry_AOP
FROM
(
SELECT IsNull(TotalCost_ACT.Segment,TotalCost_AOP.Segment) as Segment, IsNull(TotalCost_ACT.EstimateRegionName,TotalCost_AOP.EstimateRegionName) as EstimateRegionName, IsNull(TotalCost_ACT.EstimateClusterName,TotalCost_AOP.EstimateClusterName) as EstimateClusterName, IsNull(TotalCost_ACT.EstimateCountryName,TotalCost_AOP.EstimateCountryName) as EstimateCountryName, IsNull(TotalCost_ACT.SAPCountryCode,TotalCost_AOP.SAPCountryCode) as SAPCountryCode,
TotalCostPerCountry_ACT,
TotalCostPerCountry_AOP
FROM (
SELECT Segment, EstimateRegionName, EstimateClusterName, EstimateCountryName, SAPCountryCode,
sum(TotalCost) as TotalCostPerCountry_ACT
FROM [aop].[itvfProductivityCost](@Interval,@ToMonth,@ACTYear,'ACT')
GROUP BY Segment, EstimateRegionName, EstimateClusterName, EstimateCountryName, SAPCountryCode
) as TotalCost_ACT
FULL OUTER JOIN
(
SELECT Segment, EstimateRegionName, EstimateClusterName, EstimateCountryName, SAPCountryCode,
sum(TotalCost) as TotalCostPerCountry_AOP
FROM [aop].[itvfProductivityCost](@Interval,@ToMonth,@AOPYear,@PLANNING_EstimateType)
GROUP BY Segment, EstimateRegionName, EstimateClusterName, EstimateCountryName, SAPCountryCode
) as TotalCost_AOP
ON TotalCost_ACT.Segment=TotalCost_AOP.Segment and TotalCost_ACT.EstimateRegionName=TotalCost_AOP.EstimateRegionName and TotalCost_ACT.SAPCountryCode=TotalCost_AOP.SAPCountryCode
) as Financial
LEFT JOIN
(
SELECT
IsNull(vwHoursPartsPerTEU_ACT.Segment,vwHoursPartsPerTEU_AOP.Segment) as Segment,
IsNull(vwHoursPartsPerTEU_ACT.Region,vwHoursPartsPerTEU_AOP.Region) as Region,
IsNull(vwHoursPartsPerTEU_ACT.Cluster,vwHoursPartsPerTEU_AOP.Cluster) as Cluster,
IsNull(vwHoursPartsPerTEU_ACT.Country,vwHoursPartsPerTEU_AOP.Country) as Country,
IsNull(vwHoursPartsPerTEU_ACT.SAPCountryCode,vwHoursPartsPerTEU_AOP.SAPCountryCode) as SAPCountryCode,
IsNull(vwHoursPartsPerTEU_ACT.BU,vwHoursPartsPerTEU_AOP.BU) as BU,
IsNull(vwHoursPartsPerTEU_ACT.[Equipment Class],vwHoursPartsPerTEU_AOP.[Equipment Class]) as [Equipment Class],
IsNull(vwHoursPartsPerTEU_ACT.ProductGroupCode,vwHoursPartsPerTEU_AOP.ProductGroupCode) as ProductGroupCode,
IsNull(vwHoursPartsPerTEU_ACT.ProductGroupCodeDesc,vwHoursPartsPerTEU_AOP.ProductGroupCodeDesc) as ProductGroupCodeDesc,
IsNull(vwHoursPartsPerTEU_ACT.ServiceCode,vwHoursPartsPerTEU_AOP.ServiceCode) as ServiceCode,
IsNull(vwHoursPartsPerTEU_ACT.ServiceCodeDesc,vwHoursPartsPerTEU_AOP.ServiceCodeDesc) as ServiceCodeDesc,
IsNull(vwHoursPartsPerTEU_ACT.[TEU or Install],0) AS [TEU or Install_ACT],
IsNull(vwHoursPartsPerTEU_AOP.[TEU or Install],0) AS [TEU or Install_AOP],
IsNull(vwHoursPartsPerTEU_ACT.[Hours],0) AS [Hours_ACT],
IsNull(vwHoursPartsPerTEU_AOP.[Hours],0) AS [Hours_AOP],
IsNull(vwHoursPartsPerTEU_AOP.[OriginalHours],0) AS [OriginalHours_AOP],
Sum(IsNull(vwHoursPartsPerTEU_ACT.[Hours],0)) Over(Partition By IsNull(vwHoursPartsPerTEU_ACT.Segment,vwHoursPartsPerTEU_AOP.Segment),IsNull(vwHoursPartsPerTEU_ACT.SAPCountryCode,vwHoursPartsPerTEU_AOP.SAPCountryCode)) as [TotalHoursPerCountry_ACT],
Sum(IsNull(vwHoursPartsPerTEU_AOP.[Hours],0)) Over(Partition By IsNull(vwHoursPartsPerTEU_ACT.Segment,vwHoursPartsPerTEU_AOP.Segment),IsNull(vwHoursPartsPerTEU_ACT.SAPCountryCode,vwHoursPartsPerTEU_AOP.SAPCountryCode)) as [TotalHoursPerCountry_AOP],
IsNull(vwHoursPartsPerTEU_ACT.[Part Cost],0) AS [Part Cost_ACT],
IsNull(vwHoursPartsPerTEU_AOP.[Part Cost],0) AS [Part Cost_AOP],
IsNull(vwHoursPartsPerTEU_AOP.[OriginalPart Cost],0) AS [OriginalPart Cost_AOP],
Sum(IsNull(vwHoursPartsPerTEU_ACT.[Part Cost],0)) Over(Partition By IsNull(vwHoursPartsPerTEU_ACT.Segment,vwHoursPartsPerTEU_AOP.Segment),IsNull(vwHoursPartsPerTEU_ACT.SAPCountryCode,vwHoursPartsPerTEU_AOP.SAPCountryCode)) as [FEPartCostPerCountry_ACT],
Sum(IsNull(vwHoursPartsPerTEU_AOP.[Part Cost],0)) Over(Partition By IsNull(vwHoursPartsPerTEU_ACT.Segment,vwHoursPartsPerTEU_AOP.Segment),IsNull(vwHoursPartsPerTEU_ACT.SAPCountryCode,vwHoursPartsPerTEU_AOP.SAPCountryCode)) as [FEPartCostPerCountry_AOP]
FROM
(
-- Too much missing cost from PerTEU report, i.e. $200k part cost discrepancy between NonTEU and TEU report for Germany in 2015
--SELECT Region, Cluster, Country, SAPCountryCode, BU, [Equipment Class], ProductGroupCode, ProductGroupCodeDesc, PrimaryServiceCode as ServiceCode, PrimaryServiceCodeDesc as ServiceCodeDesc, Sum([TEU or Install]) as [TEU or Install], Sum([Total Labor Hours]+[Total Travel Hours]) as [Hours], Sum([Total Part Cost]) as [Part Cost]
--FROM [aop].[vwHoursPartsPerTEU]
--WHERE [Product Date] between dbo.fnCurrYearStartDateForPrevMonth(getDate()) and (select max(FromMonth) from fin.vwFinancials where FromMonth>=dbo.fnCurrYearStartDateForPrevMonth(getDate()) and EstimateType='ACT' and (Account is null or Account<>'AA_BASICCOGS') and FinanceType In('NonTradeCost','TradeCost'))
--GROUP BY Region, Cluster, Country, SAPCountryCode, BU, [Equipment Class], ProductGroupCode, ProductGroupCodeDesc, PrimaryServiceCode, PrimaryServiceCodeDesc
select Segment, EstimateRegionName as Region, EstimateClusterName as Cluster, EstimateCountryName as Country, SAPCountryCode, BU, EquipmentClass as [Equipment Class], ProductGroupCode, ProductGroupCodeDesc, ServiceCode, ServiceCodeDesc, [TEU or Install], [Hours], [Parts] as [Part Cost]
from [aop].[itvfHoursPartsPerPopulation](@Interval,@ToMonth,@ACTYear)
) AS vwHoursPartsPerTEU_ACT
FULL OUTER JOIN
(
-- Reset to Original Hours & Parts for assumptions resulting in a negative value
select [Segment], Region, Cluster, Country, SAPCountryCode, BU, [Equipment Class], ProductGroupCode, ProductGroupCodeDesc, ServiceCode, ServiceCodeDesc
,[TEU or Install_CY] as [TEU or Install]
,[OriginalHours_CY] as [OriginalHours]
,case when [Hours_CY]/nullif([TEU or Install_CY],0)<0
then [OriginalHours_CY]
else [Hours_CY]
end as [Hours]
,[OriginalPart Cost_CY] as [OriginalPart Cost]
,case when [Part Cost_CY]/nullif([TEU or Install_CY],0)<0
then [OriginalPart Cost_CY]
else [Part Cost_CY]
end as [Part Cost]
--from aop.[itvfOperationalProjections](@Interval,@AOPYear)
from aop.[itvfOperationalProjections](@Interval,@ToMonth,@AOPYear)
) AS vwHoursPartsPerTEU_AOP
ON vwHoursPartsPerTEU_ACT.Segment = vwHoursPartsPerTEU_AOP.Segment AND vwHoursPartsPerTEU_ACT.SAPCountryCode = vwHoursPartsPerTEU_AOP.SAPCountryCode AND vwHoursPartsPerTEU_ACT.BU = vwHoursPartsPerTEU_AOP.BU AND vwHoursPartsPerTEU_ACT.[Equipment Class] = vwHoursPartsPerTEU_AOP.[Equipment Class] AND vwHoursPartsPerTEU_ACT.ProductGroupCodeDesc = vwHoursPartsPerTEU_AOP.ProductGroupCodeDesc AND vwHoursPartsPerTEU_ACT.ServiceCode = vwHoursPartsPerTEU_AOP.ServiceCode
) as Operational
ON Financial.Segment=Operational.Segment and Financial.EstimateCountryName=Operational.Country
显然代码很长很复杂,所以我希望我们能够在概念上解决这个问题。
我尝试根据建议优化未知,但ad hoc仍然比ITVF快。这是我尝试的方式:
select * from [aop].[itvfOpsProductivity]('YTD',10,'2017','AOP','2016')
option (optimize for unknown)
我做了进一步的隔离测试,发现它实际上与我从ITVF运行它的事实无关,因为事实上,当我拿起ITVF的内容并用文字替换变量时,它仍然跑得很糟糕!然而,当我使用声明和设置参数运行ITVF ad hoc的内容时,性能仍然很好。我最后通过调整一些问题来解决这个问题,但是为什么这样做起来没有意义。我想,这两种方法应该都是一样的。