Vous avez besoin d'un index le long des lignes suivantes
CREATE INDEX ix
ON dbo.Participation(DateCreated)
INCLUDE (ParticipationLevel);
Et vous devez réécrire la requête pour se débarrasser de la OR
et d'éviter l'arbitre inutile nce à une colonne définie comme NOT NULL
.
(Remarque simple COUNT(Selector)
ne regarderait pas la valeur que SQL Server reconnaît qu'il ne peut pas être NULL, mais l'emballage dans une expression va à l'encontre de cette logique)
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)
Cela peut donner un plan avec une recherche en ci-dessous
Notez qu'il serait possible de se débarrasser de la sorte par le traitement des morceaux de l'indice d'un mois au moment (peut-être dans un CTE récursive), mais cela peut être exagéré.
code pour cela pourrait ressembler à quelque chose comme
/*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);
Ce qui donne un plan avec répété cherche et sans sortes
Vous pouvez simplifier les choses un peu en fixant DateStart à min-date si null, et DateEnd à max-date avant de les utiliser dans la requête ... en éliminant deux clauses OR qui sont toujours mauvaises pour la performance. Assurez-vous également que votre colonne DateCreated a un index approprié, avec ParticipationLevel en tant que colonne include. Je ne vois pas de définition pour "Suivi" ... – pmbAustin
Avez-vous des index sur votre table? Vous pouvez utiliser un index avec une clé sur 'DateCreated' et vous pouvez inclure' ParticipationLevel'. Avez-vous vraiment besoin de compter 'Tracking' ?, si cette colonne ne peut pas avoir' NULL', vous pouvez simplement utiliser 'COUNT (1)' à la place – Lamak
Les deux bons commentaires ci-dessus. Un autre élément d'information? Combien de lignes dans la table? Combien de mois distincts contient-il? –