group by慢主因是执行计划出现“using temporary”或索引不匹配导致哈希/排序分组;需按where+group by顺序建复合索引并include聚合字段,避免函数、类型转换和通配符破坏索引。

GROUP BY为什么慢?先看执行计划里有没有“Using temporary”
SQL Server 执行 GROUP BY 时,如果没走索引或索引不匹配,就会退化成哈希分组(Hash Match Aggregate)或排序分组(Sort),并触发磁盘临时表——执行计划里出现 Using temporary 或 Estimated Row Count 远高于实际过滤后行数,就是典型信号。
这不是语法问题,而是优化器“找不到捷径”,只能硬扫+分组。所以第一步不是改 SQL,是开 SET STATISTICS XML ON 看执行计划,确认瓶颈在分组前还是分组中。
索引字段顺序必须严格匹配GROUP BY和WHERE的组合逻辑
索引不是建了就生效,顺序错一点,整个索引就白搭。核心原则:WHERE 条件字段前置,GROUP BY 字段紧随其后,聚合字段用 INCLUDE 补齐。
- 写法是
WHERE status = 'active' GROUP BY region, category→ 索引必须是(status, region, category),不能是(region, category, status)或只建(region, category) - 如果还选了
SUM(price),且price不在索引里,就会回表;应改成CREATE NONCLUSTERED INDEX IX_sales_filter_group ON sales(status, region, category) INCLUDE (price) - 多字段分组时,把基数低、筛选强的放左边(比如
region只有 5 个值,category有 500 个),索引(region, category)比(category, region)更易命中
函数包裹、类型转换、LIKE通配符会让索引直接失效
GROUP BY YEAR(create_time)、GROUP BY UPPER(name)、WHERE name LIKE '%abc' 这些写法会让索引完全无法参与分组,优化器只能全表扫描。
- 日期分组别用函数:把
GROUP BY YEAR(create_time), MONTH(create_time)改成WHERE create_time >= '2026-01-01' AND create_time ,再配合索引 <code>(create_time)覆盖范围 - 字符串比较避免隐式转换:确保参数类型和字段类型一致,比如
WHERE user_id = '123'(user_id是INT)会触发转换,改用WHERE user_id = 123 -
LIKE只有前缀匹配能走索引:name LIKE 'John%'可以,name LIKE '%ohn'不行
DISTINCT有时比GROUP BY快得多,别硬扛聚合语义
如果你只是要“去重后的分组键列表”,而不是做 COUNT(*)、SUM() 等计算,DISTINCT 往往更轻量——它可以用流式聚合(Stream Aggregate),跳过哈希/排序阶段。
例如:
SELECT app_account FROM logs WHERE dt >= '2026-08-01' GROUP BY app_account
和
SELECT DISTINCT app_account FROM logs WHERE dt >= '2026-08-01'
逻辑等价,但后者常快 5–10 倍。前提是没聚合计算、没 HAVING、没其他 SELECT 列。
真正容易被忽略的是:索引是否覆盖了整个查询路径——从 WHERE 过滤,到 GROUP BY 分组,再到 SELECT 中所有字段。少一个环节,就可能多一次回表或排序。别只盯着 GROUP BY 字段本身。










