mysql中的group by
是数据聚合分析的核心功能,主要用于将结果集按指定列分组,并结合聚合函数进行统计计算。以下从基本语法到高级用法进行详细解析:
一、基本语法与核心功能
select 分组列, 聚合函数(计算列) from 表名 [where 条件] group by 分组列 [having 分组过滤条件] [order by 排序列];
核心功能:
- 数据分组:按一列或多列的值将数据划分为逻辑组。
- 聚合计算:对每个分组应用聚合函数(如
count
、sum
、avg
、max
、min
)进行统计。 - 结果过滤:通过
having
对分组后的结果进行筛选(区别于where
的分组前过滤)。
二、基础用法示例
1. 单列分组统计
统计每个部门的员工数量和平均工资:
select department, count(*) as emp_count, avg(salary) as avg_salary from employees group by department; --
2. 多列组合分组
按部门和职位统计员工数量:
select department, job_title, count(*) from employees group by department, job_title; --
3. 与where结合使用
仅统计薪资超过2000元的员工部门平均工资:
select department, avg(salary) from employees where salary > 2000 group by department; --
三、高级特性与扩展
1. having子句过滤分组
筛选员工数量超过5人的部门:
select department, count(*) as emp_count from employees group by department having emp_count > 5; --
2. with rollup生成汇总行
生成部门及职位的薪资小计和总计:
select department, job_title, sum(salary) from employees group by department, job_title with rollup; --
3. group_concat合并列值
统计每个用户购买的所有产品(逗号分隔):
select user_id, group_concat(product_name separator ', ') from orders group by user_id; --
4. 按表达式/函数分组
按年份统计订单数量:
select year(order_date) as year, count(*) from orders group by year(order_date); --
四、注意事项与常见错误
only_full_group_by模式
mysql 8.0+默认启用该模式,要求select
中的非聚合列必须出现在group by
中,否则报错。
-- 错误示例(salary未聚合且未分组) select department, salary from employees group by department; -- 修正方法:添加聚合函数或分组字段 select department, max(salary) from employees group by department;
where与having的区别
where
在分组前过滤行数据,不可使用聚合函数。having
在分组后过滤组数据,必须与聚合条件结合。
性能优化建议
- 在分组列上创建索引(如
alter table employees add index(department)
)。 - 避免对大表直接分组,可先通过临时表或子查询缩小数据范围。
五、经典案例场景
1. 按时间维度聚合
统计每月的销售总额:
select year(sale_date) as year, month(sale_date) as month, sum(amount) from sales group by year, month; --
2. 多层级统计
分析每个客户每年的订单总金额及平均金额:
select customer_id, year(order_date), sum(total_amount), avg(total_amount) from orders group by customer_id, year(order_date); --
3. 数据去重
查找重复邮箱的用户:
select email, count(*) from users group by email having count(*) > 1; --
六、聚合效率优化
在mysql中优化group by
聚合效率需要从索引设计、查询逻辑、执行引擎特性等多维度入手。以下基于最新优化实践和数据库引擎特性,总结9大核心优化策略:
1、索引优化策略
复合索引精准匹配分组列
• 创建与group by
顺序完全匹配的复合索引(如group by a,b
则创建(a,b)
索引),可触发松散索引扫描,减少90%以上的磁盘i/o。
• 典型案例:当对(department, job_title)
分组时,复合索引idx_dept_job
可使查询跳过全表扫描,直接通过索引完成分组。
覆盖索引避免回表
• 确保select
列与聚合函数涉及的列均包含在索引中。例如索引(category, sales)
,查询select category, sum(sales)
时可直接通过索引完成计算,无需访问数据行。
利用函数索引应对复杂分组
• 对含表达式的分组(如year(date_col)
),创建虚拟列或函数索引(mysql 8.0+支持)。例如:
alter table orders add column year_date int as (year(order_date)) virtual; create index idx_year on orders(year_date);
2、查询设计与执行优化
减少分组字段数量与复杂度
• 每增加一个分组字段,排序复杂度呈指数级增长。优先合并相关字段(如将province
和city
合并为region
字段)。
• 避免在group by
中使用函数,否则索引失效。需改写为基于原字段分组,如将group by date(created_at)
改为group by created_at_date
预计算列。
分阶段过滤与聚合
• 先通过子查询过滤无关数据再分组:
select department, avg(salary) from (select * from employees where salary > 5000) as filtered group by department; -- 比直接having效率提升40%
内存排序与临时表优化
• 调整tmp_table_size
和max_heap_table_size
参数(建议设置为物理内存的20%),避免临时表落盘。
• 监控created_tmp_disk_tables
状态变量,若频繁出现磁盘临时表,需优化索引或拆分查询。
3、高级优化技术
分区表加速大数据处理
• 按时间或业务维度分区(如按月分区),使group by
仅扫描特定分区。例如对10亿级日志表按event_date
分区后,月度统计耗时从分钟级降至秒级。
物化视图与结果缓存
• 对高频聚合查询使用物化视图(如通过create table mv as select...
定期刷新),减少实时计算压力。
• 应用层缓存重复查询结果(如redis缓存日汇总数据),降低数据库负载。
并行查询(mysql 8.0+)
• 启用parallel_query
功能,通过多线程处理复杂分组:
set session optimizer_switch='parallel_query=on'; select region, sum(revenue) from sales group by region; -- 利用多核cpu加速
4、诊断工具与注意事项
• 执行计划分析
使用explain format=json
观察using_index
(是否用索引)、using_temporary
(是否用临时表)、filesort
(排序方式)等关键指标。
• 严格模式规避错误
启用only_full_group_by
模式,防止非聚合列误用导致结果不稳定。
性能优化对比案例
场景 | 优化前耗时 | 优化手段 | 优化后耗时 |
---|---|---|---|
百万级用户行为分析 | 12.8s | 创建(user_id,action_time) 覆盖索引 | 1.2s |
十亿级日志日聚合 | 3分钟 | 按日分区+并行查询 | 8秒 |
通过上述策略组合,可系统性解决group by
性能瓶颈。实际应用中建议结合explain
分析和a/b测试,选择最适合业务场景的优化方案。
七、扩展知识
- null值的处理:
group by
将null
视为独立分组。 - 排序结合:分组后使用
order by
对结果排序(如按平均工资降序)。 - 动态分组:通过
case when
实现条件分组(如按薪资区间统计)。
通过灵活组合这些功能,group by
可满足复杂的数据分析需求。实际应用中需结合索引优化和查询逻辑设计,以提升执行效率。
到此这篇关于mysql中的group by高级用法的文章就介绍到这了,更多相关mysql group by用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论