1.14Group By Optimization 分组优化

大多数方法为了满足分组查询需要扫描整个表并且创建一个临时表,其中每组中的值都是连续的,如果可以使用聚合函数和临时表获取各个分组。在某些情况下,mysql能够通过使用索引方法从而避免创建临时表来提高查询效率。

在group by中使用索引的前提条件是group by中的列都是来自相同的索引,并且索引中存储的是有序的key(例如,是一个BTREE索引,而不是HASH索引)。是否能用索引方法代替临时表的依据是哪一部分的索引被用在查询中,这一部分的条件是特殊的和聚合函数。

有两种方法在group by查询中使用索引方法,在接下来的部分详细描述。第一种方法,分组操作是用于任意范围谓词的使用。第二种方法是首先完成一个范围查询,然后对结果数据进行分组。

在mysql,GROUP BY被用于排序,所以服务器会使用order by优化器来分组。然而,并不赞成依赖GROUP BY的排序。请看8.2.1.13的order by优化

>松散索引扫描

最有效的处理分组的方法是在分组的列上直接使用索引。通过这种方法,mysql使用索引类型的特有属性如有序性(例如BTREE索引)。该特性使得查找分组在一个索引值上而不需要考虑所有满足where条件的全部索引的值。这种方法只会考虑索引的一小部分值,所以也被称为松散索引扫描。当没有一个where条件时,一个松散索引扫描读取的索引数量和分组数量相同,但依然要比全部索引值要少很多。如果where条件包含了范围查找,松散索引扫描每一组中满足范围条件的第一个key,并且再读取最少的可能数量的索引。这个可能性的条件如下:

1)查询覆盖了一张简单的表

2)group by中的列形式必须是满足索引左前缀,而不能再有其他列。(如果,除了group by,查询中有不同的条件,所有不同的属性引用列的形式是一个左前缀索引)例如,如果表t1中有一个索引在(c1,c2,c3),松散索引扫描可以使用,当查询有group by c1,c2。如果查询是group by c2,c3,或者是group by c1,c2,c4,则松散索引不可用。

3) 在查询的列展示中使用的聚合函数只有MIN()和MAX(),所有他们引用的都是相同的列。该列必须是一个索引并且必须直接跟在group by的后面。

4)除了group by引用的这些,剩下的索引中的其他部分必须都是常量(也就是说,他们必须引用的是常数类型),除了讨论MIN()或者是MAX()函数。

5)对于索引列,全部值必须都是被索引的,并不仅仅是一个前缀,例如,c1 VARCHAR(20),INDEX(c1(10)),索引不能被用于松散索引。

如果一个查询中使用了松散索引查询,EXPLAIN输出中会展示Using index for group-by在Extra列中。

假设t1(c1,c2,c3,c4)中有一个索引idx(c1,c2,c3),松散索引查询能够使用在如下的查询中:

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;

下面的查询不能使用这种快速查询的方法,理由如下:

1)使用了除MIN()和MAX()之外的聚合函数:

SELECT c1, SUM(c2) FROM t1 GROUP BY c1;

2) 在group by中的列不是最左前缀索引形式的:

SELECT c1, c2 FROM t1 GROUP BY c2, c3;

3)查询引用的索引的部分和在group by之后的部分对于一个常量来说并不是等价的:

SELECT c1, c3 FROM t1 GROUP BY c1, c2;

 如果查询中使用了where c3=const ,则松散索引扫描能够使用。

松散索引扫描方法能够使用在其他形式的聚合函数引用中出现在查询列表中,除了已经支持的MIN()和MAX()函数的引用:

 1)AVG(DISTINCT),SUM(DISTINCT),和COUNT(DISTINCT)也被支持。AVG(DISTINCT)和SUM(DISTINCT)使用单一参数。COUNT(DISTINCT)能够有多余一个列的参数。

 2)必须没有group by或者是DISTINCT条件在查询中。

 3)先前对松散扫描限制的描述任然适用。

假设在表t1(c1,c2,c3,c4)中有一索引idx(c1,c2,c3),那么松散索引扫描方法能够用于如下的查询:

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

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

>紧凑索引扫描

紧凑的索引扫描也许是一个全表索引扫描,也许是一个范围的索引扫描,完全由查询条件决定:

当对松散索引的查询条件不满足时,对于group by查询依然尽可能避免创建临时表。如果有一个范围查询在where条件中,该方法将只会读取满足where条件的全部key集合。否则,它将会是一个全索引的扫描。因为该方法会读取满足where条件的所有索引的值或者是对于没有范围条件的全部索引的值,我们定义它为一个紧凑的索引扫描。通过一个紧凑的索引扫描,分组操作通过读取满足条件的全部索引值来完成。

为了使用紧凑索引扫描方法,充分条件是存在一个恒定等价的条件对于查询中引用的全部列都来自group by中的key或者部分来自其中。恒等条件能填充任何对于查询keys的空白,所以可以是前缀索引。前缀索引能够被用于索引查找。如果我们要求对group by的结果排序,且形成查询key是前缀索引形式的是可能的,mysql也避免了额外的排序操作因为查询有序的前缀索引已经对所有的key排好序了。

假设有一个索引idx(c1,c2,c3)在t1(c1,c2,c3,c4)。下面的查询不能用之前描述的松散索引查询方法,但依然能够用紧凑索引查询方法。

1)group by中有一个空白,但是被条件c2='a'覆盖了。

SELECT c1, c2, c3 FROM t1 WHERE c2 = 'a' GROUP BY c1, c3;

2)group by不是以索引的第一部分开始的,但是查询条件中听了该部分的常量条件:

SELECT c1, c2, c3 FROM t1 WHERE c1 = 'a' GROUP BY c2, c3;

到此关于group by的优化就结束了,之后我们将介绍的是1.15的DISTINC Optimization

mysql5.7官网直译SQL语句优化--分组优化的更多相关文章

  1. mysql5.7官网直译SQL语句优化--select语句优化

    8.2 sql语句优化 大致内容如下: 8.2.1:SELECT语句的优化 8.2.2:优化子查询,派生表和试图引用 8.2.3:优化INFORMATION_SCHEMA查询 8.2.4:优化数据改变 ...

  2. 《MySQL慢查询优化》之SQL语句及索引优化

    1.慢查询优化方式 服务器硬件升级优化 Mysql服务器软件优化 数据库表结构优化 SQL语句及索引优化 本文重点关注于SQL语句及索引优化,关于其他优化方式以及索引原理等,请关注本人<MySQ ...

  3. Oracle SQL语句之常见优化方法总结--不定更新

    1.SQL语句尽量用大写的: 因为oracle总是先解析SQL语句,把小写的字母转换成大写的再执行. 2.WHERE子句中的连接顺序: ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理, ...

  4. SQl语句查询性能优化

    [摘要]本文从DBMS的查询优化器对SQL查询语句进行性能优化的角度出发,结合数据库理论,从查询表达式及其多种查询条件组合对数据库查询性能优化进行分析,总结出多种提高数据库查询性能优化策略,介绍索引的 ...

  5. MySQL中一个sql语句包含in优化问题

    第一版sql: SELECT module.id, module.module_name, module.module_code `module` where IN (module.did_acces ...

  6. 3,SQL语句及数据库优化

       1,统一SQL语句的写法 对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的. 所以封装成复用方法,用标准模板来控制. select*from dual select*Fr ...

  7. Oracle SQL语句之常见优化方法总结

    1.用EXISTS替换DISTINCT 当SQL包含一对多表查询时,避免在SELECT子句中使用DISTINCT,一般用EXIST替换,EXISTS(低效): SELECT DISTINCT USER ...

  8. SQL语句及数据库优化

     1,统一SQL语句的写法 对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的. 所以封装成复用方法,用标准模板来控制. select*from dual  select*Fro ...

  9. Mysql sql语句技巧与优化

    一.常见sql技巧 1.正则表达式的使用 2.巧用RAND()提取随机行 mysql数据库中有一个随机函数rand()是获取一个0-1之间的数,利用这个函数和order by一起能够吧数据随机排序, ...

随机推荐

  1. 洛谷—— P1457 城堡 The Castle

    https://www.luogu.org/problem/show?pid=1457 题目描述 我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特 ...

  2. HDFS学习笔记(1)初探HDFS

    Hadoop分布式文件系统(Hadoop Distributed File System, HDFS) 分布式文件系统是一种同意文件通过网络在多台主机上分享的文件系统.可让多机器上的多用户分享文件和存 ...

  3. Android实现能够揉动的图片

    public class Demo01 extends Activity{ private Bitmap bitmap = null; @Override protected void onCreat ...

  4. HTTP Error 500.19

    HTTP Error 500.19 - Internal Server Error The requested page cannot be accessed because the related ...

  5. php常用知识集锦

    php常用知识集锦 很多位置都有写好的代码,自己做项目的时候可以直接拿来用,而不用自己写,比如现在看到的菜鸟教程. 1.判断是否为空 empty($_POST["name"]) 2 ...

  6. 转:utf8汉字编码16进制对照

    http://blog.chinaunix.net/uid-25544300-id-3281847.html GB    Unicode  UTF-8     Chinese Character Co ...

  7. Modules:手机号码验证

    ylbtech-Modules:手机号码验证 手机号码验证,文档以JFB项目架构为原型,介绍实现原理,如何调用和应用实例. 架构包括5个主要模块:Basebase,Base,Service,Api和W ...

  8. canvas绘制爱心

    需求:绘制爱心图像轨迹. 实现:直接贴代码吧! 预览地址:https://codepen.io/wzc570738205/pen/dqqBpj <!DOCTYPE> <html> ...

  9. java.io.IOException: Cannot find any registered HttpDestinationFactory from the Bus.

    转自:https://blog.csdn.net/u012849872/article/details/51037374

  10. 27.Qt时钟

    myclock.h #ifndef MYCLOCK_H #define MYCLOCK_H #include <QObject> #include <QLCDNumber> # ...