ITVF表现不佳与不同参数对比临时

时间:2016-11-18 03:22:07

标签: sql-server sql-server-2012 inline-table-function

我有一个内联表值函数,由于某种原因它运行速度非常慢,我只需要取消它。

当我在临时的基础上运行相同的确切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的内容时,性能仍然很好。我最后通过调整一些问题来解决这个问题,但是为什么这样做起来没有意义。我想,这两种方法应该都是一样的。

0 个答案:

没有答案