使用变量与常量缓慢执行TVF

时间:2015-04-27 16:11:46

标签: sql sql-server tsql

我有一个很长的复杂查询,我已经分解为TVF,以便于维护和创建其他报告所基于的基础数据。但是,当我参数化输入时,执行查询需要更长的时间; top查询在~3秒内执行,第二个查询在40秒内执行。

我认为这可能是由于参数嗅探,虽然这些是内联TVF,所以我不确定它是多么相关。我尝试用存储过程包装进行测试并明确地将参数声明为DATETIME,但我似乎无法到达任何地方。

DECLARE @Month int = 4
DECLARE @year int = 2015

DECLARE @startDate DateTime, @endDate DateTime

SELECT @startDate = Dateadd(mm, ( @year - 1900 ) * 12 + @month - 1, 0 )
SELECT @endDate = DATEADD(DAY, -1, Dateadd(mm, ( @year - 1900 ) * 12 + @month, 0 ))

/* Constants */
SELECT
    *,
    DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') EstDrivingTimeDay,
    DATEADD(MINUTE, duration / [days], '1900-01-01') EstTimeOnSiteDay,
    DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') + DATEADD(MINUTE, duration / [days], '1900-01-01') TotalWorkingTime
FROM
    GetDriverCreditsByMonthYearBaseViewTrips('2015-04-01', '2015-04-30' )

/* Stored Proc Wrapper */
EXEC DriverTripsByMonthYear @month, @year

/* Params in SQL */
SELECT
    *,
    DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') EstDrivingTimeDay,
    DATEADD(MINUTE, duration / [days], '1900-01-01') EstTimeOnSiteDay,
    DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') + DATEADD(MINUTE, duration / [days], '1900-01-01') TotalWorkingTime
FROM
    GetDriverCreditsByMonthYearBaseViewTrips(@startDate, @endDate )  option (optimize for (@startDate unknown, @endDate unknown))

sproc DriverTripsByMonthYear

CREATE PROCEDURE DriverTripsByMonthYear
    -- Add the parameters for the stored procedure here
    @month INT,
    @year INT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @startDate DATETIME
    DECLARE @endDate DATETIME

    SELECT @startDate = Dateadd(mm, ( @year - 1900 ) * 12 + @month - 1, 0 )
    SELECT @endDate = DATEADD(DAY, -1, Dateadd(mm, ( @year - 1900 ) * 12 + @month, 0 ))

    -- Insert statements for procedure here
    SELECT
        *,
        DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') EstDrivingTimeDay,
        DATEADD(MINUTE, duration / [days], '1900-01-01') EstTimeOnSiteDay,
        DATEADD(MINUTE, ((CONVERT(DECIMAL, Mileage) / [Days]) / 56) * 60, '1900-01-01') + DATEADD(MINUTE, duration / [days], '1900-01-01') TotalWorkingTime
    FROM
        GetDriverCreditsByMonthYearBaseViewTrips(@startDate, @endDate )  option (optimize for (@startDate unknown, @endDate unknown))
END
GO

总之,我需要将月份和年份转换为DateTime,并将其作为参数传递给内联TVF,而不需要花费10倍的执行时间。

N.B 两个查询都生成相同的执行计划

1 个答案:

答案 0 :(得分:1)

我要做的第一件事就是检查你是否成为parameter sniffing的受害者。如果确实如此,修复它的方法之一就是使用

option (optimize for (@startDate unknown, @endDate unknown))

在您的TVF正文中