我有一张表dbo.participation
:
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
User VARCHAR(MAX) NOT NULL,
ParticipationLevel TINYINT NOT NULL,
Selector VARCHAR(MAX) NOT NULL,
DateCreated DATETIME NOT NULL
我在下面创建了代码,但不幸的是,它显示了@DateStart
和@DateStop
SELECT
dateadd(month, datediff(month, 0, DateCreated), 0) AS MDate
,COUNT(CASE WHEN ParticipationLevel >= 10 THEN Selector ELSE NULL END) AS ParticipationLevel1
,COUNT(CASE WHEN ParticipationLevel >= 30 THEN Selector ELSE NULL END) AS ParticipationLevel2
FROM
Participation
WHERE
(@DateStart IS NULL OR (@DateStart IS NOT NULL
AND DateCreated >= @DateStart))
AND (@DateEnd IS NULL OR (@DateEnd IS NOT NULL
AND DateCreate < @DateEnd))
GROUP BY
Dateadd(month, datediff(month, 0, DateCreate), 0)
您是否碰巧有任何想法如何改进我的代码,或者如何修改表格以提高性能?
答案 0 :(得分:1)
您需要沿着以下行的索引
CREATE INDEX ix
ON dbo.Participation(DateCreated)
INCLUDE (ParticipationLevel);
您应该重写查询以摆脱OR
并避免不必要地引用定义为NOT NULL
的列。
(注意,一个简单的COUNT(Selector)
不会查找该值,因为SQL Server认为它不能为NULL但是在表达式中包装会使这个逻辑失效)
SELECT DATEADD(month, DATEDIFF(month, 0, DateCreated), 0) AS MDate,
COUNT(CASE
WHEN ParticipationLevel >= 10 THEN 1
END) AS ParticipationLevel1,
COUNT(CASE
WHEN ParticipationLevel >= 30 THEN 1
END) AS ParticipationLevel2
FROM Participation
WHERE DateCreated >= ISNULL(@DateStart, '17530101')
AND DateCreated <= ISNULL(@DateEnd, '99991231')
GROUP BY DATEDIFF(month, 0, DateCreated)
这可以给出一个寻求下面的计划
请注意,可以通过在当时处理索引的块(可能在递归CTE中)来摆脱排序,但这可能是过度的。
代码可能类似于
/*Cheap to find out from the index*/
IF @DateStart IS NULL
SELECT @DateStart = MIN(DateCreated)
FROM dbo.Participation
IF @DateStart IS NULL
SELECT @DateEnd = MAX(DateCreated)
FROM dbo.Participation
/*Adjust to start of month*/
SELECT @DateStart = DATEADD(month, DATEDIFF(month, 0, @DateStart), 0),
@DateEnd = DATEADD(month, 1 + DATEDIFF(month, 0, @DateEnd), 0);
WITH Dates
AS (SELECT @DateStart AS MDate
UNION ALL
SELECT dateadd(MONTH, 1, MDate) AS MDate
FROM Dates
WHERE dateadd (MONTH, 1, MDate) <= @DateEnd)
SELECT D.MDate,
CA.ParticipationLevel1,
CA.ParticipationLevel2
FROM Dates D
CROSS APPLY (SELECT COUNT(CASE
WHEN ParticipationLevel >= 10
THEN 1
END) AS ParticipationLevel1,
COUNT(CASE
WHEN ParticipationLevel >= 30
THEN 1
END) AS ParticipationLevel2
FROM Participation P WITH (INDEX = ix)
WHERE P.DateCreated >= D.MDate
AND P.DateCreated < DATEADD(MONTH, 1, D.MDate)
GROUP BY () /* So no grouping row returned for empty months */
) CA(ParticipationLevel1, ParticipationLevel2)
OPTION (MAXRECURSION 0);
这给出了一个反复寻求并且没有排序的计划
答案 1 :(得分:0)
WHERE 子句中不需要两项检查
@DateStart IS NOT NULL和
@DateEnd IS NOT NULL和
SELECT dateadd(month, datediff(month, 0, DateCreated), 0) AS MDate
,COUNT(CASE WHEN ParticipationLevel >= 10 THEN Tracking ELSE NULL END) AS ParticipationLevel1
,COUNT(CASE WHEN ParticipationLevel >= 30 THEN Tracking ELSE NULL END) AS ParticipationLevel2
FROM Participation
WHERE (@DateStart IS NULL OR DateCreated >= @DateStart) AND (@DateEnd IS NULL OR DateCreate < @DateEnd)
GROUP BY Dateadd(month, datediff(month, 0, DateCreate), 0)