优化GROUP BY性能

时间:2015-01-26 13:09:40

标签: sql sql-server-2008

GROUP BY是否有一些棘手的方法是由别名定义的变量或者是计算结果?我认为下面的代码通过在Select语句中计算MyMonth然后再在Group语句中进行二次演示。这可能是不必要的浪费。简单的GROUP BY MyMonth是不可能的。是否可以强制只计算一次month([MyDate])

更新代码。聚合函数已添加。

SELECT month([MyDate]) AS MyMonth, count([MyDate]) AS HowMany
FROM tableA
WHERE [MyDate] BETWEEN '2014-01-01' AND '2014-12-31'
GROUP BY month([MyDate])
ORDER BY MyMonth

2 个答案:

答案 0 :(得分:1)

不,您不能直接在GROUP BY子句中使用列别名。而是在from列表中执行select,并使用组中的结果列。

select MyMonth, MAX(someothercolumn)
from
(
SELECT month([MyDate]) AS MyMonth,
       someothercolumn
FROM tableA
WHERE [MyDate] BETWEEN '2014-01-31' AND '2014-12-31'
)
GROUP BY MyMonth
ORDER BY MyMonth

答案 1 :(得分:0)

您真正的问题可能源于在每一行调用MONTH(...)。这可以防止优化器使用索引来完成计数(它可以将它用于WHERE子句,但这仍然是很多行。

相反,您应该将其转换为范围查询,优化程序可以将其用于与索引进行比较。首先,我们构建一个简单的范围表:

WITH Months as (SELECT MONTH(d) AS month, 
                       d AS monthStart, DATEADD(month, 1, d) AS monthEnd
                FROM (VALUES(CAST('20140101' AS DATE))) t(d)
                UNION ALL
                SELECT MONTH(monthEnd), 
                       monthEnd, DATEADD(month, 1, monthEnd)
                FROM Months
                WHERE monthEnd < CAST('20150101' AS DATE))

SQL Fiddle Example
(如果你有一个现有的日历表,你可以根据它进行查询,但有时候一个简单的特别计划效果最好)

一旦我们有了范围表,您就可以使用它来约束和存储数据,如下所示:

SELECT Months.month, COUNT(*)
FROM TableA
JOIN Months
  ON TableA.MyDate >= Months.monthStart
     AND TableA.MyDate < Months.monthEnd
GROUP BY Months.month

注意:日期范围的开头已更改为2014-01-01,因为看起来很奇怪,您只会在1月份的一天内汇总数月...