SQL 2012 SP3 DATEADD谓词导致计数查询中的高估计

时间:2016-06-24 09:29:54

标签: sql-server

我已获得最新的SQL 2012标准版:

  

Microsoft SQL Server 2012(SP3-CU3)(KB3152635) - 11.0.6537.0(X64)     2016年4月28日17:57:34版权所有(c)Microsoft Corporation Standard   Windows NT 6.1上的版本(64位)(Build 7601:Service Pack 1)   (管理程序)

在基于每个客户的用户数量的2个变量(月份和年份)的简单计数中,应用程序是特定的用户,行估计值是实际结果的10倍。我已经释放了缓存,重建了索引,确保它正在进行索引查找并尝试重新编译计划。如果我手动输入谓词,我会得到预期的结果和计划,但如果我使用dateadd,我会得到一个版本,因为我在使用CTE的视图中有多个计数,我希望找到一个方法我相信dateadd正在造成大量的行数估计。

    SELECT
    [Customer],
    [Month],
    [Year],
    COUNT([Username]) AS 'RDS'
    FROM [MS_CitrixUsers]
    WHERE [Application] = 'RDS'
    AND [Month] = DATENAME(month, dateadd(month, -1,GETDATE()))
    AND [YEAR] = DATENAME(year, dateadd(month, -1,GETDATE()))
    GROUP BY [MS_CitrixUsers].[Customer],
    [MS_CitrixUsers].[Month],
    [MS_CitrixUsers].[Year]

计数在包含膨胀行数的排序后触发流聚合。

Plan

Stream Properties

我的观点如下:

    WITH RDS1 
    AS
    (
    SELECT
    [Customer],
    COUNT([Username]) AS 'RDS1'
    FROM [MS_CitrixUsers]
    WHERE [Application] = 'RDS'
    AND [Month] = @month 
    AND [YEAR] = @year
    GROUP BY [MS_CitrixUsers].[Customer],
    [MS_CitrixUsers].[Month],
    [MS_CitrixUsers].[Year]
    ),
    RDS2 
    AS
    (
    SELECT
    [Customer],
    [Month],
    [Year],
    COUNT([Username]) AS 'RDS2'
    FROM [MS_CitrixUsers]
    WHERE [Application] = 'RDS'
    AND [Month] = @monthbefore
    AND [YEAR] = @year2
    GROUP BY [MS_CitrixUsers].[Customer],
    [MS_CitrixUsers].[Month],
    [MS_CitrixUsers].[Year]
    ),
    ...

    SELECT c.Customer,
    CASE WHEN NOT EXISTS (SELECT [RDS1] FROM [RDS1] t1 WHERE t1.Customer =     c.Customer) 
AND EXISTS (SELECT [RDS2] FROM [RDS2] t2 WHERE t2.Customer = c.Customer) THEN '99999' ELSE ([RDS1] - Coalesce([RDS2], 0)) END AS 'RDS',
CASE WHEN NOT EXISTS (SELECT [CitrixUsage1] FROM [CitrixUsage] t1 WHERE t1.Customer = c.Customer) 
AND EXISTS (SELECT [CitrixUsage2] FROM [CitrixUsage2] t2 WHERE t2.Customer = c.Customer) THEN '99999' ELSE ([CitrixUsage1] - Coalesce([CitrixUsage2], 0)) END    AS 'Citrix Usage',

我得到的预期结果是两个月的数据差异:

  

[客户] [application1] ... [applicationN]

     

Customer1 -1 3

我们有相当多的应用程序,因此您可以想象返回结果需要相当长的时间,所以我看到优化估算值是否会有所帮助。

解决方法:我发现在这里的另一个答案是,使用临时表,将变量放在那里,并加入我的表,避免了流聚合,并使用哈希匹配来估计正确行数。

2 个答案:

答案 0 :(得分:0)

你应该尽量不在谓词中计算。你没有提到这是否是一个视图,但你不能声明变量;

DECLARE @MonthVariable varchar(10); SET @MonthVariable = DATENAME(month, dateadd(month, -1,GETDATE()))
DECLARE @YearVariable int; SET @YearVariable = DATENAME(year, dateadd(month, -1,GETDATE()))

SELECT
    [Customer],
    [Month],
    [Year],
    COUNT([Username]) AS 'RDS'
FROM [MS_CitrixUsers]
WHERE [Application] = 'RDS'
    AND [Month] = @MonthVariable
    AND [YEAR] = @YearVariable
GROUP BY [MS_CitrixUsers].[Customer],
    [MS_CitrixUsers].[Month],
    [MS_CitrixUsers].[Year]

所以这是一个观点,试试这个;

SELECT
    [Customer],
    [Month],
    [Year],
    COUNT([Username]) AS 'RDS'
FROM [MS_CitrixUsers] a
INNER JOIN (SELECT
             DATENAME(month, dateadd(month, -1,GETDATE())) CurMon
            ,DATENAME(year, dateadd(month, -1,GETDATE())) CurYear
            ) b
    ON a.[Month] = b.CurMon
    AND a.[Year] = b.CurYear
WHERE [Application] = 'RDS'
GROUP BY [MS_CitrixUsers].[Customer],
    [MS_CitrixUsers].[Month],
     [MS_CitrixUsers].[Year]

答案 1 :(得分:0)

我的解决方法版本:

CREATE TABLE #MasterDate( [Month1] varchar(50), [YEAR1] varchar(10),[Month2] varchar(50),[YEAR2] varchar(10))
INSERT INTO #MasterDate ([Month1],[YEAR1],[Month2],[YEAR2] )
    SELECT DATENAME(month, dateadd(month, -1,GETDATE())) 
    ,DATENAME(year, dateadd(month, -1,GETDATE()))
    ,DATENAME(month, dateadd(month, -2,GETDATE())) 
    ,DATENAME(year, dateadd(month, -2,GETDATE()))

;WITH RDS1 
AS
(
SELECT
[Customer]
,[MS_CitrixUsers].[Month]
,[MS_CitrixUsers].[YEAR]
,COUNT([Username]) AS 'RDS1'
FROM [MS_CitrixUsers]
INNER JOIN #MasterDate m ON [Month] = m.[Month1] and [YEAR] = m.[YEAR1]
WHERE [Application] = 'RDS'
GROUP BY [MS_CitrixUsers].[Customer],
[MS_CitrixUsers].[Month],
[MS_CitrixUsers].[Year]
),

RDS2 
AS
(
SELECT
[Customer],
[Month],
[Year],
COUNT([Username]) AS 'RDS2'
FROM [MS_CitrixUsers]
INNER JOIN #MasterDate m ON [Month] = m.[Month2] and [YEAR] = m.[YEAR2]
WHERE [Application] = 'RDS'
GROUP BY [MS_CitrixUsers].[Customer],
[MS_CitrixUsers].[Month],
[MS_CitrixUsers].[Year]
)
SELECT c.Customer,
CASE WHEN NOT EXISTS (SELECT [RDS1] FROM [RDS1] t1 WHERE t1.Customer = c.Customer) 
AND EXISTS (SELECT [RDS2] FROM [RDS2] t2 WHERE t2.Customer = c.Customer) THEN '99999' ELSE ([RDS1] - Coalesce([RDS2], 0)) END AS 'RDS'
FROM [Customers] c
INNER JOIN #MasterDate m ON [Month] = m.[Month2] and [YEAR] = m.[YEAR2]
LEFT JOIN RDS1 t1 ON t1.Customer = c.Customer
LEFT JOIN RDS2 t2 ON t2.Customer = c.Customer

DROP TABLE #MasterDate

当然,这不是一个视图,只有SP。现在的问题是,它是否解决了我的速度问题,只需另外50个cte进行编辑。

编辑:完成我的SP版本的视图,内部连接到#temp表而不是dateadd视图。

查看完成时间:37秒

SP:11秒。