GROUP BY多字段分组按列组合唯一值分组,每行代表一个组合(如“某部门下的某职位”),必须确保SELECT中非聚合字段全部出现在GROUP BY中,否则报错或结果不可靠。

GROUP BY 多字段分组不是“加几个字段就行”,它会改变分组粒度和结果行数,必须明确业务意图再写。
GROUP BY department, job_title 时,每组对应唯一组合
比如 SELECT department, job_title, COUNT(*) FROM employees GROUP BY department, job_title,结果中每一行代表“某部门下的某职位”,而不是“某部门”或“某职位”单独的统计。这意味着:
- 如果某部门有 5 个职位,就会产生最多 5 行;若某职位在多个部门都存在,也会分别计数
- 不能在 SELECT 中出现未分组也未聚合的字段,例如
name或hire_date—— 数据库会报错(MySQL 5.7+ 严格模式下)或返回任意值(旧版本或非严格模式) - 分组顺序不影响计算逻辑,但会影响结果排序(除非显式加
ORDER BY)
HAVING 必须作用于聚合结果,不能写 WHERE 条件
想筛出“平均薪资超 15k 的部门-职位组合”,得用 HAVING AVG(salary) > 15000,而不是 WHERE salary > 15000。因为:
-
WHERE在分组前执行,只能过滤原始行(比如先剔除实习岗:WHERE employment_type != 'intern') -
HAVING在分组后执行,才能访问AVG(salary)、COUNT(*)这类聚合值 - 常见错误:把
HAVING COUNT(*) > 10写成WHERE COUNT(*) > 10,直接报错Invalid use of group function
多字段分组 + GROUP_CONCAT 可合并明细,但要注意长度限制
有时需要在分组结果里附带“该组有哪些 ID”,可用 GROUP_CONCAT(user_id):
SELECT department, job_title, COUNT(*) AS cnt, GROUP_CONCAT(user_id) AS user_ids FROM employees GROUP BY department, job_title;
但注意:
-
GROUP_CONCAT默认最大长度是 1024 字符(MySQL),超长会被截断,需提前设SET SESSION group_concat_max_len = 1000000 - 结果是字符串,无法直接用于后续数值计算;如需还原为列表,得靠应用层拆分
- 不保证顺序,加
ORDER BY子句可控制拼接顺序:GROUP_CONCAT(user_id ORDER BY hire_date DESC)
性能敏感场景下,多字段分组必须配复合索引
当 GROUP BY a, b 频繁出现,且常带 WHERE 过滤(如 WHERE status = 'active'),索引设计直接影响执行计划:
- 最优索引通常是
(status, a, b)—— 把 WHERE 条件列放最左,再跟分组列 - 仅建
(a, b)索引,WHERE status = 'active'仍可能触发全表扫描 - 用
EXPLAIN检查type是否为ref或range,避免ALL;同时看Extra是否含Using filesort或Using temporary—— 后者说明数据库被迫建临时表做分组,很慢
真正容易被忽略的是:多字段分组的结果集大小可能远超预期。比如按 user_id, date, product_id 分组,即使只有 10 万用户,一天也可能生成百万级组合行。上线前务必用 SELECT COUNT(*) 预估结果规模,别等报表卡死才反应过来。

















