MySQL有关Group By的优化

昨天我写了有关MySQL的loose index scan的相关博文(http://www.cnblogs.com/wingsless/p/5037625.html),后来我发现上次提到的那个优化方法中主要的目的就是实现loose index scan,而在执行计划的层面上看,Extra信息中应该是“Using index for group-by”。这样看来,可能MySQL在处理distinct时和group by用了同样的优化手段,即走索引,进行loose index scan。那么今天我研究了一下官方文档,发现确实如此。

其实对于group by来讲,最一般的实现方法就是进行一次全表扫描,将所有的group by的行按照顺序存放在一个temporary table中,然后在进行分组识别或者进行聚合操作。这样问题就是太复杂,时间上要好久,空间上的消耗也不小。这时,MySQL可以利用索引来优化group by。

这里就可以讲讲什么叫做loose index scan了,根据官方的定义,这种方法只需要扫描索引中的少部分数据,而不是所有满足where条件的数据,所以这个方法叫做loose index scan。

下面是什么情况下可以使用loose index scan的情况:

1 单一表查询

2 Group by中只有最左前缀列,没有其他列

3 只支持max和min聚合,而且,要聚合的列必须是group by中列所在的索引。

4 未被group by引用的索引其他部分必须是常量(这句我不是很理解)

5 不支持前缀索引。

假设t1(c1, c2, c3, c4)表有一个索引包括c1, c2, c3列,以下这些查询都是可以进行loose index scan的:

SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;

这些都是抄的官方文档,正确性未完全验证。

下面这些SQL都没有办法使用loose index scan:

-- 因为聚合函数不是max或者min
SELECT c1, SUM(c2) FROM t1 GROUP BY c1;

-- 因为不符合最左前缀原则
SELECT c1, c2 FROM t1 GROUP BY c2, c3;

-- 查询涉及到了索引的一部分,紧跟group by中的列,但是没有常量等值语句,加上 WHERE c3 = const就好了
SELECT c1, c3 FROM t1 GROUP BY c1, c2;

另外一些聚合函数也是可以用到loose index scan的,比如:AVG(DISTINCT), SUM(DISTINCT), 和COUNT(DISTINCT)

以下这些语句也可以:

SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1;

SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;

很多语句都是从5.7的文档上摘抄下来的,正确性没有得到验证,虽说官方文档是权威,但是尽信书不如无书,以及纸上得来终觉浅,绝知此事须躬行,明天周末,我逐条测试,然后再更。

时间: 2024-08-06 07:51:53

MySQL有关Group By的优化的相关文章

MySQL my.cnf参数配置优化详解

http://leeyin.iteye.com/blog/1459274 [b]PS:本配置文件针对Dell R710,双至强E5620.16G内存的硬件配置.CentOS 5.6 64位系统,MySQL 5.5.x 稳定版.适用于日IP 50-100w,PV 100-300w的站点,主要使用InnoDB存储引擎.其他应用环境请根据实际情况来设置优化.[/b] # 以下选项会被MySQL客户端应用读取. # 注意只有MySQL附带的客户端应用程序保证可以读取这段内容. # 如果你想你自己的MyS

索引优化来实现MySQL的ORDER BY语句优化

MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通过索引优化来实现MySQL的ORDER BY语句优化: 1.ORDER BY的索引优化.如果一个SQL语句形如: SELECT [column1],[column2],-. FROM [TABLE] ORDER BY [sort]; 在[sort]这个栏位上建立索引就可以实现利用索引进行order

Mysql千万级大表优化

Mysql的单张表的最大数据存储量尚没有定论,一般情况下mysql单表记录超过千万以后性能会变得很差.因此,总结一些相关的Mysql千万级大表的优化策略. 1.优化sql以及索引 1.1优化sql 1.有索引但未被用到的情况(不建议) (1)避免like的参数以通配符开头时 尽量避免Like的参数以通配符开头,否则数据库引擎会放弃使用索引而进行全表扫描. 以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '%0'\G

主从同步、读写分离、mysql性能调优(软优化)

配置mysql主从同步1 主从同步的作用:让slave身份的数据库服务器自动同步 master身份的数据库服务器上的数据. 一.主数据库服务器的配置192.168.4.121 用户授权mysql> grant replication slave on *.* to [email protected]"192.168.4.11" identified by "123456";2 启用binlog日志vim /etc/my.cnf[mysqld]server_id

MySQL索引原理及SQL优化

原文:MySQL索引原理及SQL优化 目录 索引(Index) 索引的原理 b+树 MySQL如何使用索引 如何优化 索引虽好,不可滥用 如何验证索引使用情况? SQL优化 explain查询执行计划 id select_type table type possible_keys key key_len ref rows Extra 优化数据库结构 优化数据大小 优化数据类型 索引(Index) MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.索引的建立对

mysql中group by和order by混用 结果不是理想结果

在使用mysql排序的时候会想到按照降序分组来获得一组数据,而使用order by往往得到的不是理想中的结果,那么怎么才能使用group by 和order by得到理想中的数据结果呢? 例如 有一个 帖子的回复表,posts( id , tid , subject , message ,  dateline ) , id为 自动增长字段, tid为该回复的主题帖子的id(外键关联),  subject 为回复标题, message 为回复内容, dateline 为回复时间,用UNIX 时间戳

mysql获取group by的总记录行数方法

mysql获取group by内部可以获取到某字段的记录分组统计总数,而无法统计出分组的记录数. mysql的SQL_CALC_FOUND_ROWS 使用 获取查询的行数 在很多分页的程序中都这样写: 代码如下 复制代码 SELECT COUNT(*) from `table` WHERE ......; 查出符合条件的记录总数 代码如下 复制代码 SELECT * FROM `table` WHERE ...... limit M,N; 查询当页要显示的数据 这样的语句可以改成: 代码如下 复

mysql分解连接的总结(来自于高性能MySQL以及自己网站性能优化)

许多高性能的站点都用了"分解连接"技术,也就是把单个多表连接查询改成多个但表查询,然后在程序中合并数据,比如: select a.*,b.* from A a join B b on a.id = b.id 可以替换为: select a.* from A; select b.* from B; 然后再把数据通过程序合并. 可能有些人认为这太浪费了,把一个查询语句变成两条查询语句或者更多的查询语句了,如果哪位猿类这样想了,那你就应该继续往下看了. 将连接查询重构为多表查询,总体有以下性

mysql使用GROUP BY分组实现取前N条记录的方法

MySQL中GROUP BY分组取前N条记录实现 mysql分组,取记录 GROUP BY之后如何取每组的前两位下面我来讲述mysql中GROUP BY分组取前N条记录实现方法. 这是测试表(也不知道怎么想的,当时表名直接敲了个aa,汗~~~~): 结果: 方法一: SELECT a.id,a.SName,a.ClsNo,a.Score FROM aa a LEFT JOIN aa b ON a.ClsNo=b.ClsNo AND a.Score<b.Score group by a.id,a.