mysql group by 汇总 优化_一次 group by + order by 性能优化分析

本文通过一个具体的SQL查询案例,详细分析了MySQL中GROUP BY语句的执行原理、性能瓶颈及优化策略。主要内容包括:索引选择、排序实现、临时表的使用、内存限制对性能的影响,以及SQL_BIG_RESULT等优化选项的作用。通过实验数据展示了不同优化方案的效果,提出了在不同数据量下选择合适优化策略的建议。
摘要由CSDN通过智能技术生成

工作了两三年,技术停滞不前,迷茫没有方向,不如看下我的直播 PHP 进阶之路 (金三银四跳槽必考,一般人我不告诉他)

最近通过一个日志表做排行的时候发现特别卡,最后问题得到了解决,梳理一些索引和MySQL执行过程的经验,但是最后还是有5个谜题没解开,希望大家帮忙解答下

主要包含如下知识点

用数据说话证明慢日志的扫描行数到底是如何统计出来的

从 group by 执行原理找出优化方案

排序的实现细节

gdb 源码调试

背景

需要分别统计本月、本周被访问的文章的 TOP10。日志表如下

CREATE TABLE `article_rank` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`aid` int(11) unsigned NOT NULL,

`pv` int(11) unsigned NOT NULL DEFAULT '1',

`day` int(11) NOT NULL COMMENT '日期 例如 20171016',

PRIMARY KEY (`id`),

KEY `idx_day_aid_pv` (`day`,`aid`,`pv`),

KEY `idx_aid_day_pv` (`aid`,`day`,`pv`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

准备工作

为了能够清晰的验证自己的一些猜想,在虚拟机里安装了一个 debug 版的 mysql,然后开启了慢日志收集,用于统计扫描行数

安装

下载源码

编译安装

创建 mysql 用户

初始化数据库

初始化 mysql 配置文件

修改密码

开启慢日志

编辑配置文件,在[mysqld]块下添加

slow_query_log=1

slow_query_log_file=xxx

long_query_time=0

log_queries_not_using_indexes=1

性能分析

发现问题

假如我需要查询2018-12-20 ~ 2018-12-24这5天浏览量最大的10篇文章的 sql 如下,首先使用explain看下分析结果

mysql> explain select aid,sum(pv) as num from article_rank where day>=20181220 and day<=20181224 group by aid order by num desc limit 10;

+----+-------------+--------------+------------+-------+-------------------------------+----------------+---------+------+--------+----------+-----------------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+--------------+------------+-------+-------------------------------+----------------+---------+------+--------+----------+-----------------------------------------------------------+

| 1 | SIMPLE | article_rank | NULL | range | idx_day_aid_pv,idx_aid_day_pv | idx_day_aid_pv | 4 | NULL | 404607 | 100.00 | Using where; Using index; Using temporary; Using filesort |

+----+-------------+--------------+------------+-------+-------------------------------+----------------+---------+------+--------+----------+-----------------------------------------------------------+

系统默认会走的索引是idx_day_aid_pv,根据Extra信息我们可以看到,使用idx_day_aid_pv索引的时候,会走覆盖索引,但是会使用临时表,会有排序。

我们查看下慢日志里的记录信息

# Time: 2019-03-17T03:02:27.984091Z

# User@Host: root[root] @ localhost [] Id: 6

# Query_time: 56.959484 Lock_time: 0.000195 Rows_sent: 10 Rows_examined: 1337315

SET timestamp=1552791747;

select aid,sum(pv) as num from article_rank where day>=20181220 and day<=20181224 group by aid order by num desc limit 10;

为什么扫描行数是 1337315

我们查询两个数据,一个是满足条件的行数,一个是group by统计之后的行数。

mysql> select count(*) from article_rank where day>=20181220 and day<=20181224;

+----------+

| count(*) |

+----------+

| 785102 |

+----------+

mysql> select count(distinct aid) from article_rank where day>=20181220 and day<=20181224;

+---------------------+

| count(distinct aid) |

+---------------------+

| 552203 |

+---------------------+

发现满足条件的总行数(785102)+group by 之后的总行数(552203)+limit 的值 = 慢日志里统计的 Rows_examined。

要解答这个问题,就必须搞清楚上面这个 sql 到底分别都是如何运行的。

执行流程分析

索引示例

为了便于理解,我按照索引的规则先模拟idx_day_aid_pv索引的一小部分数据

day

aid

pv

id

20181220

1<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值