【MySQL】大数据统计 - 优化GROUP BY的使用
2018-01-08 17:49
281 查看
1 目录
目录背景说明
环境预置
查询测试
1 旧查询
11 WHERE的顺序
12 优化结果
2 新查询
3 总结
2 背景说明
昨天刚对统计语句做了优化,限制在0.5s左右,今天再试的时候发现消耗突然暴涨到2.8s左右。对每个子查询分别运行之后发现时间主要消耗在一个拥有128W数据的业务日志表上。也不知道是不是昨天测试的时候数据量没这么多,今天决定再做一次优化。3 环境预置
业务日志表是系统与外部系统进行业务交互时用于保存交互结果的表。CREATE TABLE `business_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `cpe_id` varchar(50) NOT NULL COMMENT '终端ID', `module_type` int(11) NOT NULL COMMENT '模块类型:1-业务模块,2-终端接口模块', `operate_time` datetime NOT NULL COMMENT '操作时间', `operate_type` int(11) NOT NULL COMMENT '操作类型:1-注册,2-定时连接,3-开机连接,4-关机', `result` int(11) NOT NULL COMMENT '结果:0-成功,其它-失败', `error_desc` varchar(200) DEFAULT NULL COMMENT '错误描述', `connect_info` text COMMENT '连接信息', PRIMARY KEY (`id`), KEY `Index_cpe_id` (`cpe_id`), KEY `Index_operate_time` (`operate_time`) ) ENGINE=InnoDB AUTO_INCREMENT=1753 DEFAULT CHARSET=utf8 COMMENT='业务日志';
向其中随机为各种操作类型生成记录共128W条。实际需求中还需要联表查询,其他表的数据不多,因此本次测试只关注耗时最多的查询部分。
注:由于测试的时候数据量一直在增加,可能时间会有出入。
4 查询测试
要求查询指定时间段内操作类型为3且操作结果为0的所有记录,并按照终端ID分组统计数量。4.1 旧查询
SELECT cpe_id, COUNT(*) restarts FROM business_log WHERE operate_time>='2012-12-05 00:00:00' AND operate_time<'2018-01-05 00:00:00' AND operate_type=3 AND result=0 GROUP BY cpe_id
如上述语句所示,旧查询将GROUP BY子句与WHERE子句放在同一SQL语句中。
按照相关博客的解释,GROUP BY子句是对查询的结果进行分组操作。但实际运行时发现上述语句耗时过长,因此着手优化该语句。
4.1.1 WHERE的顺序
按照相关博客的建议,过滤性较强的条件放在前面。经过测试,各条件查询结果的数据量分别如下:条件 | 数据量 | operate_type=3 | 6698 |
---|---|
result=0 | 6679 |
operate_time>='2012-12-05 00:00:00' | 1336649 |
operate_time<'2018-01-05 00:00:00' | 224908 |
疑点:MySQL执行多条件过滤时,是不是在过滤结果上进行再过滤?
4.1.2 优化结果
尝试对原SQL语句进行优化后发现,统计速度依旧没有获得满意的提升。单独运行条件查询语句(不包含GROUP BY和COUNT函数)后发现,查询的结果数据量只有6655条,耗时0.825s;加上统计语句后,时间飙升至3s。疑点:MySQL的GROUP BY是不是在WHERE的过滤结果上进行的分组统计?
注:MySQL说明文档中关于优化GROUP BY的部分指出:The most general way to satisfy a GROUP BY clause is to scan the whole table and create a new temporary table where all rows from each group are consecutive, and then use this temporary table to discover groups and apply aggregate functions (if any)。即,GROUP BY语句会扫描全表并新建一个临时表用来分组存放数据,然后根据临时表中的分组对数据执行聚合函数。现在的问题聚焦在:如果GROUP BY和WHERE在同一个语句中,这个“全表”指的是物理表还是WHERE过滤后的数据集合?
4.2 新查询
根据上面的结果,由于怀疑GROUP BY并没有基于WHERE的过滤结果进行分组查询,于是显式地利用子查询语句将WHERE的过滤结果交给GROUP BY统计:SELECT cpe_id, COUNT(*) restarts FROM ( SELECT cpe_id FROM business_log WHERE operate_time>='2012-12-05 00:00:00' AND operate_time<'2018-01-05 00:00:00' AND operate_type=3 AND result=0 ) t GROUP BY cpe_id
如上述语句所示,在查询语句外包了一个统计语句。执行结果:0.851s。时间消耗大幅减少!
4.3 总结
利用GROUP BY统计大数据时,应当将查询与统计分离,优化查询语句。相关文章推荐
- Mysql 中使用DATE_FORMAT函数按月、周统计数据
- Mysql 中使用DATE_FORMAT函数按月、周统计数据
- MySQL 优化相关——统计数据分析
- Mysql 中使用DATE_FORMAT函数按月、周统计数据
- MySQL中几种数据统计查询的基本使用教程
- 使用shell进行mysql数据统计并上传
- Mysql 中使用DATE_FORMAT函数按月、周统计数据
- mysql按日期分组(group by)查询统计的时候,没有数据补0的解决办法。
- MYSQL中GROUP BY进行数据统计
- Mysql数据分组GROUP BY 和HAVING,与WHERE组合使用
- mysql按日期分组(group by)查询统计的时候,没有数据补0的解决办法。
- Mysql 中使用DATE_FORMAT函数按月、周统计数据
- 大数据之数据库mysql优化实战之索引的使用
- MySQL中几种数据统计查询的基本使用教程
- Python+Mysql生成zabbix统计数据(优化) 推荐
- mysql按日期分组(group by)查询统计的时候,没有数据补0的解决办法
- 使用批处理进行mysql数据统计并上传
- 14-mysql优化之使用存储过程向mysql数据库中添加4000000条数据
- 解决Mysql数据量大的时候 分页优化(使用limit)的问题
- Mysql 中使用DATE_FORMAT函数按月、周统计数据