您的位置:首页 > 大数据

【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的顺序

按照相关博客的建议,过滤性较强的条件放在前面。经过测试,各条件查询结果的数据量分别如下:

<
aac8
tr>
条件数据量
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统计大数据时,应当将查询与统计分离,优化查询语句。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: