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 相关文章推荐
MySQL kill不掉线程的原因
May 07 MySQL
解读MySQL的客户端和服务端协议
May 10 MySQL
MySql学习笔记之事务隔离级别详解
May 12 MySQL
MySQL 使用索引扫描进行排序
Jun 20 MySQL
MySQL中存储时间的最佳实践指南
Jul 01 MySQL
MySQL系列之一 MariaDB-server安装
Jul 02 MySQL
Node-Red实现MySQL数据库连接的方法
Aug 07 MySQL
MySQL into_Mysql中replace与replace into用法案例详解
Sep 14 MySQL
MySQL和Oracle批量插入SQL的通用写法示例
Nov 17 MySQL
MySQL Innodb索引机制详细介绍
Nov 23 MySQL
SQL注入详解及防范方法
Dec 06 MySQL
MySQL主从切换的超详细步骤
Jun 28 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
PHP5.3.1 不再支持ISAPI
2010/01/08 PHP
ThinkPHP3.0略缩图不能保存到子目录的解决方法
2012/09/30 PHP
PHP实现的简单缓存类
2015/07/29 PHP
PHP实现基于回溯法求解迷宫问题的方法详解
2017/08/17 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
laravel框架学习笔记之组件化开发实现方法
2020/02/01 PHP
JS解析XML的实现代码
2009/11/12 Javascript
对JavaScript客户端应用编程的一些建议
2015/06/24 Javascript
jQuery实现响应鼠标背景变化的动态菜单效果代码
2015/08/27 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
原生js实现密码输入框值的显示隐藏
2017/07/17 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
mpvue 单文件页面配置详解
2018/12/02 Javascript
mongodb初始化并使用node.js实现mongodb操作封装方法
2019/04/02 Javascript
Vue的Eslint配置文件eslintrc.js说明与规则介绍
2020/02/03 Javascript
VUE 项目在IE11白屏报错 SCRIPT1002: 语法错误的解决
2020/09/27 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
2020/11/12 Javascript
Python中生成Epoch的方法
2017/04/26 Python
django实现前后台交互实例
2017/08/07 Python
Python学习之用pygal画世界地图实例
2017/12/07 Python
pandas数据分组和聚合操作方法
2018/04/11 Python
使用50行Python代码从零开始实现一个AI平衡小游戏
2018/11/21 Python
Python 调用 Windows API COM 新法
2019/08/22 Python
pytorch快速搭建神经网络_Sequential操作
2020/06/17 Python
如何使用 Flask 做一个评论系统
2020/11/27 Python
世界领先的26岁以下学生和青少年旅行预订网站:StudentUniverse
2018/07/01 全球购物
西班牙宠物用品和食品网上商店:Tiendanimal
2019/06/06 全球购物
Timberland澳大利亚官网:全球领先的户外品牌
2019/12/10 全球购物
Linden Leaves官网:新西兰纯净护肤品
2020/12/20 全球购物
《落花生》教学反思
2014/02/25 职场文书
小学校长竞聘演讲稿
2014/05/16 职场文书
学校节能减排方案
2014/06/13 职场文书
2014最新预备党员思想汇报范文:中国梦,我的梦
2014/10/25 职场文书
地道战观后感300字
2015/06/04 职场文书
机械原理课程设计心得体会
2016/01/15 职场文书
SQL Server代理:理解SQL代理错误日志处理方法
2021/06/30 SQL Server