我有以下T-SQL查询:
SELECT Wk.WeekID,
Wk.WeekStart,
SUM(CASE WHEN NOT(Task.WeekDate IS NULL) THEN 1 ELSE 0 END) AS WeekCount,
SUM(CASE WHEN NOT(Task.DayDate IS NULL) THEN 1 ELSE 0 END) AS DayCount
FROM tblPerWeek AS Wk
LEFT OUTER JOIN tblPerTask AS Task ON (Task.WeekDate = Wk.WeekStart)
OR (Task.DayDate BETWEEN Wk.WeekStart AND Wk.WeekEnd)
WHERE (Wk.WeekStart <= @DateEnd) AND (Wk.WeekEnd >= @DateStart)
GROUP BY Wk.WeekID, Wk.WeekStart
tblPerWeek
表的结构:
WeekID int
WeekStart date
WeekEnd date
tblPerTask
表的结构:
TaskID int
WeekDate date
DayDate date
基本上,查询计算分配给周(WeekCount
)或周内特定日期(DayCount
)的任务。
tblPerWeek
有大约2800条记录,tblPerTask
有大约70000条记录。
现在,在join中存在(Task.DayDate BETWEEN Wk.WeekStart AND Wk.WeekEnd)
条件的问题/故障:
有什么收获?关于如何更快地进行此查询的任何解决方案?
答案 0 :(得分:1)
通常使用UNION查询来解决使用OR的问题。如果两组记录互斥,则使用UNION ALL甚至更快。
SELECT Wk.WeekID,
Wk.WeekStart,
SUM(CASE WHEN NOT(Task.WeekDate IS NULL) THEN 1 ELSE 0 END) AS WeekCount,
SUM(CASE WHEN NOT(Task.DayDate IS NULL) THEN 1 ELSE 0 END) AS DayCount
FROM tblPerWeek AS Wk
LEFT OUTER JOIN tblPerTask AS Task ON Task.WeekDate = Wk.WeekStart
WHERE (Wk.WeekStart <= @DateEnd) AND (Wk.WeekEnd >= @DateStart)
GROUP BY Wk.WeekID, Wk.WeekStart
UNION
SELECT Wk.WeekID,
Wk.WeekStart,
SUM(CASE WHEN NOT(Task.WeekDate IS NULL) THEN 1 ELSE 0 END) AS WeekCount,
SUM(CASE WHEN NOT(Task.DayDate IS NULL) THEN 1 ELSE 0 END) AS DayCount
FROM tblPerWeek AS Wk
LEFT OUTER JOIN tblPerTask AS Task ON Task.DayDate BETWEEN Wk.WeekStart AND Wk.WeekEnd
WHERE (Wk.WeekStart <= @DateEnd) AND (Wk.WeekEnd >= @DateStart)
GROUP BY Wk.WeekID, Wk.WeekStart
答案 1 :(得分:1)
优化器讨厌OR
SELECT Wk.WeekID,
Wk.WeekStart,
SUM(CASE WHEN TaskW.WeekDate IS NULL THEN 0 ELSE 1 END) AS WeekCount,
SUM(CASE WHEN TaskD.DayDate IS NULL THEN 0 ELSE 1 END) AS DayCount
FROM tblPerWeek AS Wk
LEFT OUTER JOIN tblPerTask AS TaskW ON TaskW.WeekDate = Wk.WeekStart
LEFT OUTER JOIN tblPerTask AS TaskD ON TaskD.DayDate BETWEEN Wk.WeekStart AND Wk.WeekEnd
WHERE Wk.WeekStart <= @DateEnd AND Wk.WeekEnd >= @DateStart
GROUP BY Wk.WeekID, Wk.WeekStart
我想你可以做一个计数,因为计数null是0
SELECT Wk.WeekID, Wk.WeekStart,
COUNT(TaskW.WeekDate) AS WeekCount,
COUNT(TaskD.DayDate) AS DayCount
FROM tblPerWeek AS Wk
LEFT OUTER JOIN tblPerTask AS TaskW ON TaskW.WeekDate = Wk.WeekStart
LEFT OUTER JOIN tblPerTask AS TaskD ON TaskD.DayDate BETWEEN Wk.WeekStart AND Wk.WeekEnd
WHERE Wk.WeekStart <= @DateEnd AND Wk.WeekEnd >= @DateStart
GROUP BY Wk.WeekID, Wk.WeekStart