我已获得最新的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]
计数在包含膨胀行数的排序后触发流聚合。
我的观点如下:
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
我们有相当多的应用程序,因此您可以想象返回结果需要相当长的时间,所以我看到优化估算值是否会有所帮助。
解决方法:我发现在这里的另一个答案是,使用临时表,将变量放在那里,并加入我的表,避免了流聚合,并使用哈希匹配来估计正确行数。
答案 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秒。