MySQL 分组查询的优化方法


Posted in MySQL onMay 12, 2021

MySQL 在处理 GROUP BY 和 DISTINCT 查询的方式在大多数情况下类似,事实上,在优化过程中有时候会把在这两种方式中转换。两类查询都能够从索引中受益,通常,这也是优化这两种查询最为重要的方式。

在无法使用索引时,MySQL 对于 GROUP BY 查询有两种策略:使用临时表或者 filesort 执行分组。对于给定的查询,两种方式都没法更高效。我们可以通过配置 SQL_BIG_RESULT 和 SQL_SMALL_RESULT 来指定优化器选择其中一个方式。

通常,对查询表的id 进行分组比使用值进行分组效率更高,例如下面的查询效率就比较低:

SELECT actor.first_name, actor.last_name, COUNT(*)
FROM sakila.file_actor
INNER JOIN sakila.actor USING(actor_id)
GROUP BY actor.first_name, actor.last_name;

而下面的查询方式则更有效:

SELECT actor.first_name, actor.last_name, COUNT(*)
FROM sakila.file_actor
INNER JOIN sakila.actor USING(actor_id)
GROUP BY film_actor.actor_id;

而使用 actor.actor_id 进行分组会比 film_actor.actor_id更高效。

这个查询能够发挥其优势的依据是演员(actor)的姓名是依赖于 actor_id 的,因此会返回相同的结果,但是如果返回的结果不同的话就不能这么做了。甚至有些时候服务端通过 SQL_MODE 配置禁用了 GROUP BY。此时如果不关心获取的值,而且用于分组的列的值是唯一的,这可以使用 MIN和 MAX 来解决这个问题。

SELECT MIN(actor.first_name), MAX(actor.last_name), ...;

对于完美主义者,他们会认为你的分组是错误的,他们也是对的。一个虚拟的 MIN 或 MAX 的结果是查询并不会正确地组装。然而,有时候你只是为了让 MySQL 更快地执行查询。完美主义者对于下面的查询会满意:

SELECT actor.fisrt_name, actor.last_name, c.cnt
FROM sakila.actor
	INNER JOIN (
    SELECT actor_id, COUNT(*) AS cnt
    FROM sakila.film_actor
    GROUP BY actor_id
  ) AS c USING(actor_id);

然而,子查询中创建和填充临时表的代价可能比理论上看起来的死办法更高。需要记住的是,子查询构建的临时表是没有索引的,这会导致性能上的下降。

通常在分组查询中,选择没有分组的列是一个糟糕的主意。这是因为查询结果是不确定的,一旦改变了索引或优化器使用了不同的策略都会导致结果被改变。事实上,我们建议将服务端的 SQL_MODE 设置为 ONLY_FULL_GROUP_BY,这时写了一个糟糕的分组查询时,系统会产生一个错误而不是直接执行。开启 ONLY_FULL_GROUP_BY 后,SELECT 的字段只能是 GROUP BY 指定的字段,此时可以通过构建分步查询或子查询的方式,先分组查出分组的列,再做二次查询。

MySQL 会根据 GROUP BY 指定的列次序自动分组,除非是使用了 ORDER BY 指定排序规则。如果不在乎次序并且发现了这导致了一个 filesort,这时候可以使用 ORDER BY NULL 来跳过自动排序。也可以通过在 GROUP BY 后面增加 DESC 或 ASC 来指定结果按指定的方向排序。

有时候可以在分组查询时要求 MySQL 在结果中做一次超级聚合。这可以通过在 GROUP BY 后面增加WITH ROLLUP 子句完成,但是这不一定能够达到优化的预期。可以通过 EXPLAIN 检查执行的方法,注意分组有没有通过 filesort 或临时表完成。然后在对相同的查询移除 WITH ROLLUP 后进行对比。通过对比也许可以找到优化的办法。

有些时候通过增加聚合查询会使得效率更高,虽然这种方式会返回更多的行。也可以通过在 FROM 后面嵌套子查询来保持中间查询结果,然后再使用 UNION 获取最终结果。

但是注意的是,在应用程序中最好是移除 WITH ROLLUP,而通过优化来完成分组查询。

结语:使用 GROUP BY 进行分组查询时最好是使用索引列分组,若无需指定次序可以使用 ORDER BY NULL 进行优化。倘若不按索引列分组的时候,则需要考虑变通的办法,并且考虑是否要使用子查询或使用 WITH ROLLUP 检查性能后再做优化。同时,为了防止分组查询出现不可预料的错误,最好是开启 ONLY_FULL_GROUP_BY。

以上就是MySQL 分组查询的优化方法的详细内容,更多关于MySQL 分组查询的优化的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
May 06 MySQL
如何用Navicat操作MySQL
May 12 MySQL
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
Jun 21 MySQL
为什么代码规范要求SQL语句不要过多的join
Jun 23 MySQL
MySQL的全局锁和表级锁的具体使用
Aug 23 MySQL
MYSQL 的10大经典优化案例场景实战
Sep 14 MySQL
MySQL中varchar和char类型的区别
Nov 17 MySQL
mysql5.6主从搭建以及不同步问题详解
Dec 04 MySQL
MySQL创建表操作命令分享
Mar 25 MySQL
MySQL视图概念以及相关应用
Apr 19 MySQL
在MySQL中你成功的避开了所有索引
Apr 20 MySQL
mysql查看表结构的三种方法总结
Jul 07 MySQL
JDBC连接的六步实例代码(与mysql连接)
May 12 #MySQL
MySQL索引知识的一些小妙招总结
MySQL COUNT函数的使用与优化
May 10 #MySQL
解读MySQL的客户端和服务端协议
MySQL 重写查询语句的三种策略
May 10 #MySQL
详解MySQL 联合查询优化机制
mysql对于模糊查询like的一些汇总
May 09 #MySQL
You might like
全国FM电台频率大全 - 18 湖南省
2020/03/11 无线电
使用 MySQL 开始 PHP 会话
2006/12/21 PHP
PHP生成不重复随机数的方法汇总
2014/11/19 PHP
PHP简单选择排序算法实例
2015/01/26 PHP
Yii2 GridView实现列表页直接修改数据的方法
2016/05/16 PHP
Linux下安装Memcached服务器和客户端与PHP使用示例
2019/04/15 PHP
PHP常用字符串输出方法分析(echo,print,printf及sprintf)
2021/03/09 PHP
在IE,Firefox,Safari,Chrome,Opera浏览器上调试javascript
2008/12/02 Javascript
XHTML下,JS浮动代码失效的问题
2009/11/12 Javascript
Three.js源码阅读笔记(物体是如何组织的)
2012/12/27 Javascript
Jquery选择子控件"大于号"和" "区别介绍及使用示例
2013/06/25 Javascript
基于jQuery实现音乐播放试听列表
2016/04/14 Javascript
js HTML5 Canvas绘制转盘抽奖
2020/09/13 Javascript
JQueryEasyUI框架下的combobox的取值和绑定的方法
2017/01/22 Javascript
React 使用browserHistory项目访问404问题解决
2018/06/01 Javascript
vue倒计时刷新页面不会从头开始的解决方法
2020/03/03 Javascript
vue中解决拖拽改变存在iframe的div大小时卡顿问题
2020/07/22 Javascript
小程序实现点击tab切换左右滑动
2020/11/16 Javascript
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
在Python的Django框架中编写编译函数
2015/07/20 Python
python 环境变量和import模块导入方法(详解)
2017/07/11 Python
django使用html模板减少代码代码解析
2017/12/12 Python
解决Python 爬虫URL中存在中文或特殊符号无法请求的问题
2018/05/11 Python
对Tensorflow中的变量初始化函数详解
2018/07/27 Python
Python中几种属性访问的区别与用法详解
2018/10/10 Python
在python中用print()输出多个格式化参数的方法
2019/07/16 Python
python mqtt 客户端的实现代码实例
2019/09/25 Python
Python+OpenCV图像处理—— 色彩空间转换
2020/10/22 Python
Under Armour澳大利亚官网:美国知名的高端功能性运动品牌
2018/02/22 全球购物
Columbia Sportswear法国官网:全球户外品牌
2020/09/25 全球购物
学校七一活动方案
2014/01/19 职场文书
《晏子使楚》教学反思
2014/02/08 职场文书
2014年大班元旦活动方案
2014/02/26 职场文书
党支部鉴定意见
2015/06/02 职场文书
男方家长婚礼致辞
2015/07/27 职场文书
Java设计模式中的命令模式
2022/04/28 Java/Android