【问题标题】:SQL 2012 SP3 DATEADD predicate causing high estimate in count querySQL 2012 SP3 DATEADD 谓词导致计数查询中的高估计
【发布时间】:2016-06-24 18:19:43
【问题描述】:

我有最新的 SQL 2012 标准版:

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

根据每个客户的用户数量的 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',

我得到的预期结果视图是 2 个月的数据之间的差异:

[客户] [应用程序1] ... [应用程序N]

客户1 -1 3

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

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

【问题讨论】:

标签: sql-server


【解决方案1】:

您应该尽量不要在谓词中进行计算。你没有提到这是否是一个视图,但你可以不声明变量吗?

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]

【讨论】:

  • 您好 Rich,感谢您的快速回复。这是一个视图,所以恐怕声明已经出来了。
  • @Glix 好的,试试我发布的第二个
  • 感谢 Rich,尝试了内部连接,但即使使用选项重新编译,它仍然会将其泵入流聚合中。猜猜我坚持加入临时表并使其成为SP。请参阅本文的第 4 部分:stackoverflow.com/questions/29117042/…
【解决方案2】:

我的解决方法版本:

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 秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2012-10-07
    • 2022-01-10
    • 2013-11-20
    相关资源
    最近更新 更多