【问题标题】:Optimizing GROUP BY performance优化 GROUP BY 性能
【发布时间】:2015-01-26 13:09:40
【问题描述】:

是否有一些棘手的方法来 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

【问题讨论】:

标签: sql sql-server-2008


【解决方案1】:

您真正的问题可能源于在每一行都调用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,因为您在汇总月份时只包含一月的一天似乎很奇怪......

【讨论】:

    【解决方案2】:

    不,您不能直接在 GROUP BY 子句中使用列别名。而是在 from 列表中进行选择,然后使用 group by 中的结果列。

    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
    

    【讨论】:

    • 聚合函数应该去哪里?
    • @PrzemyslawRemin,在外部/主要选择中。 (就像 GROUP BY 已经是一样。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-31
    • 2011-08-29
    • 1970-01-01
    • 2021-10-11
    相关资源
    最近更新 更多