如何使用group by进行去重

因为mysql的distinct在结果集中,全部不同,才可以去重。
所以,当我们进行去重处理的时候,需要单独对某列进行去重,可以使用group by子句进行分组去重
select _auto_id from account_login group by _auto_id; 该语句可以对_auto_id列进行去重。

在使用group by进行去重效率分析

无索引
0.23s

mysql> explain select _auto_id from account_login group by _auto_id;
+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+
|  1 | SIMPLE      | account_login | ALL  | NULL          | NULL | NULL    | NULL | 133257 | Using temporary; Using filesort |
+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+

mysql> show profile;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000154 |
| checking permissions | 0.000012 |
| Opening tables       | 0.000029 |
| init                 | 0.000029 |
| System lock          | 0.000014 |
| optimizing           | 0.000010 |
| statistics           | 0.000021 |
| preparing            | 0.000020 |
| Creating tmp table   | 0.000036 |
| Sorting result       | 0.000007 |
| executing            | 0.000005 |
| Sending data         | 0.207841 |
| Creating sort index  | 0.021024 |
| end                  | 0.000010 |
| removing tmp table   | 0.000130 |
| end                  | 0.000010 |
| query end            | 0.000016 |
| closing tables       | 0.000019 |
| freeing items        | 0.000035 |
| cleaning up          | 0.000039 |
+----------------------+----------+
20 rows in set, 1 warning (0.00 sec)

此处创建了sort index进行排序,说明对MySQL使用了内存临时表,group by后面的排序过程是使用sort index来完成的,而且该内存临时表的大小是由MAX_HEAP_TABLE_SIZE来控制。

Sending data 显示的这个时间 = Time(Sending data) + Time (Sorting result), 这样其实应该是排序所用的时间

因为在group by后会进行自动排序,如果该我们仅仅想去重,而不需要排序,可以使用

mysql> explain select _auto_id from account_login group by _auto_id order by null;
+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+
| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows   | Extra           |
+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+
|  1 | SIMPLE      | account_login | ALL  | NULL          | NULL | NULL    | NULL | 133257 | Using temporary |
+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000155 |
| checking permissions | 0.000012 |
| Opening tables       | 0.000029 |
| init                 | 0.000029 |
| System lock          | 0.000014 |
| optimizing           | 0.000009 |
| statistics           | 0.000022 |
| preparing            | 0.000020 |
| Creating tmp table   | 0.000042 |
| executing            | 0.000006 |
| Sending data         | 0.219640 |
| end                  | 0.000021 |
| removing tmp table   | 0.000014 |
| end                  | 0.000008 |
| query end            | 0.000014 |
| closing tables       | 0.000020 |
| freeing items        | 0.000033 |
| cleaning up          | 0.000020 |
+----------------------+----------+

可以发现,在加入order by null子句后,MySQL并没有创建sort index进行排序(内存排序非常快,优化效果并不明显,并且这个阶段只是每个数据块的排序,)。但是在group by后添加多列,并且不能进行

有索引
mysql> explain select _auto_id from account_login group by _auto_id;
使用时间 0.11s
执行计划

+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table         | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------------+
|  1 | SIMPLE      | account_login | index | idx_acc       | idx_acc | 4       | NULL | 133257 | Using index |
+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------------+

profile

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000140 |
| checking permissions | 0.000011 |
| Opening tables       | 0.000027 |
| init                 | 0.000028 |
| System lock          | 0.000014 |
| optimizing           | 0.000009 |
| statistics           | 0.000035 |
| preparing            | 0.000028 |
| Sorting result       | 0.000006 |
| executing            | 0.000005 |
| Sending data         | 0.105595 |
| end                  | 0.000012 |
| query end            | 0.000013 |
| closing tables       | 0.000015 |
| freeing items        | 0.000026 |
| cleaning up          | 0.000034 |
+----------------------+----------+

explain select _auto_id from account_login group by _auto_id   时间0.11s
explain select _auto_id from account_login group by _auto_id order by null  时间0.11s
在使用索情况下,因为使用了索引自身的有序性,所以不需MySQL再次创建临时表(create sort index)进行排序,可以直接输出有序结果,两者的计算时间相同。

正常使用场景效率分析

mysql> explain select _auto_id,max(date) from account_login group by _auto_id;
没有索引
用时 3.16s

+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+
|  1 | SIMPLE      | account_login | ALL  | NULL          | NULL | NULL    | NULL | 133257 | Using temporary; Using filesort |
+----+-------------+---------------+------+---------------+------+---------+------+--------+---------------------------------+

mysql> show profile;

+---------------------------+----------+
| Status                    | Duration |
+---------------------------+----------+
| starting                  | 0.000111 |
| checking permissions      | 0.000010 |
| Opening tables            | 0.000018 |
| init                      | 0.000030 |
| System lock               | 0.000011 |
| optimizing                | 0.000007 |
| statistics                | 0.000014 |
| preparing                 | 0.000013 |
| Creating tmp table        | 0.000037 |
| Sorting result            | 0.000007 |
| executing                 | 0.000005 |
| Sending data              | 0.545211 |
| converting HEAP to MyISAM | 1.307225 |
| Sending data              | 0.738511 |
| Creating sort index       | 0.573640 |
| end                       | 0.000020 |
| removing tmp table        | 0.001682 |
| end                       | 0.000009 |
| query end                 | 0.000012 |
| closing tables            | 0.000016 |
| freeing items             | 0.000030 |
| logging slow query        | 0.000051 |
| cleaning up               | 0.000018 |
+---------------------------+----------+

在group by过程中,先使用sort index对group by子句进行处理,然后创建临时表,然后转换到磁盘临时表使用文件排序取出max(date)
如果group by后面列数过多(即使不排序),也是会用converting HEAP to MyISAM
converting HEAP to MyISAM 该语句表明了在执行过程中,内存临时表转变成了硬盘临时表。可以使用 tmp_table_size,MAX_HEAP_TABLE_SIZE来改变内存临时表的最大大小,但是在该SQL下,因为要使用文件排序,所以无论内存临时表设置多大,都会进行内存临时表到文件临时表的转变。

有索引情况
时间 0.31s
mysql>  explain select _auto_id,max(date) from account_login group by _auto_id;

+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------+
| id | select_type | table         | type  | possible_keys | key     | key_len | ref  | rows   | Extra |
+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------+
|  1 | SIMPLE      | account_login | index | idx_acc       | idx_acc | 4       | NULL | 133257 | NULL  |
+----+-------------+---------------+-------+---------------+---------+---------+------+--------+-------+

profile

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000109 |
| checking permissions | 0.000010 |
| Opening tables       | 0.000022 |
| init                 | 0.000031 |
| System lock          | 0.000012 |
| optimizing           | 0.000007 |
| statistics           | 0.000021 |
| preparing            | 0.000022 |
| Sorting result       | 0.000006 |
| executing            | 0.000005 |
| Sending data         | 0.314817 |
| end                  | 0.000024 |
| query end            | 0.000015 |
| closing tables       | 0.000032 |
| freeing items        | 0.000042 |
| cleaning up          | 0.000023 |
+----------------------+----------+
在有索引的情况下,仅仅靠索引本身就完成了全部需求。

distinct进行分析

explain select distinct(_auto_id) from account_login;

+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+
| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows   | Extra           |
+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+
|  1 | SIMPLE      | account_login | ALL  | NULL          | NULL | NULL    | NULL | 133257 | Using temporary |
+----+-------------+---------------+------+---------------+------+---------+------+--------+-----------------+

mysql> show profile;

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000087 |
| checking permissions | 0.000009 |
| Opening tables       | 0.000016 |
| init                 | 0.000016 |
| System lock          | 0.000011 |
| optimizing           | 0.000007 |
| statistics           | 0.000013 |
| preparing            | 0.000014 |
| Creating tmp table   | 0.000026 |
| executing            | 0.000006 |
| Sending data         | 0.221214 |
| end                  | 0.000024 |
| removing tmp table   | 0.000190 |
| end                  | 0.000011 |
| query end            | 0.000014 |
| closing tables       | 0.000019 |
| freeing items        | 0.000036 |
| cleaning up          | 0.000024 |
+----------------------+----------+

select distinct _auto_id,sid,uid from account_login;
+---------------------------+----------+
| Status                    | Duration |
+---------------------------+----------+
| starting                  | 0.000095 |
| checking permissions      | 0.000010 |
| Opening tables            | 0.000019 |
| init                      | 0.000019 |
| System lock               | 0.000010 |
| optimizing                | 0.000006 |
| statistics                | 0.000015 |
| preparing                 | 0.000016 |
| Creating tmp table        | 0.000030 |
| executing                 | 0.000006 |
| Sending data              | 0.529466 |
| converting HEAP to MyISAM | 1.928813 |
| Sending data              | 0.157253 |
| end                       | 0.000020 |
| removing tmp table        | 0.002778 |
| end                       | 0.000009 |
| query end                 | 0.000012 |
| closing tables            | 0.000016 |
| freeing items             | 0.000031 |
| logging slow query        | 0.000062 |
| cleaning up               | 0.000033 |
+---------------------------+----------+

发现distinct和没有排序的group by几乎是一样的,并且在进行多列的去重的时候也使用了 converting HEAP to MyISAM进行汇总

总结:
create sort index 使用内存临时表进行分块排序,分块排序后再进入磁盘进行汇总排序
converting HEAP to MyISAM 是进入硬盘进行汇总排序,如果group by数据列过多,即使不排序,也需要使用磁盘临时表进行汇总数据。
group by的主要消耗是在临时表排序阶段,而不是分组阶段。
所以制约group by性能的问题,就是临时表+排序,尽量减少磁盘排序,较少磁盘临时表的创建,是比较有用的处理办法。
最好的办法就是在group by条件后,添加索引或者复合索引,这样MySQL就会利用索引完成排序,分组

原文:https://blog.csdn.net/u013983450/article/details/52190699

group by与distinct效率分析及优化措施的更多相关文章

  1. Mysql 多表联合查询效率分析及优化

    1. 多表连接类型 1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如: SELECT * FROM table1 CROSS JO ...

  2. SQL -去重Group by 和Distinct的效率

    经实际测试,同等条件下,5千万条数据,Distinct比Group by效率高,但是,这是有条件的,这五千万条数据中不重复的仅仅有三十多万条,这意味着,五千万条中基本都是重复数据. 为了验证,重复数据 ...

  3. 重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化

    重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化 一:Mysql原理与慢查询 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

  4. Mysql慢SQL分析及优化

    为何对慢SQL进行治理 从数据库角度看:每个SQL执行都需要消耗一定I/O资源,SQL执行的快慢,决定资源被占用时间的长短.假设总资源是100,有一条慢SQL占用了30的资源共计1分钟.那么在这1分钟 ...

  5. MYSQL索引结构原理、性能分析与优化

    [转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...

  6. mysql性能优化-慢查询分析、优化索引和配置

    一.优化概述 二.查询与索引优化分析 1性能瓶颈定位 Show命令 慢查询日志 explain分析查询 profiling分析查询 2索引及查询优化 三.配置优化 1)      max_connec ...

  7. 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化

    高性能Linux服务器 第10章    基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...

  8. in和exists的区别与SQL执行效率分析

    可总结为:当子查询表比主查询表大时,用Exists:当子查询表比主查询表小时,用in SQL中in可以分为三类: 1.形如select * from t1 where f1 in ('a','b'), ...

  9. [转]mysql性能优化-慢查询分析、优化索引和配置

    一. 优化概述 MySQL数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候.磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应用分布在 ...

随机推荐

  1. Redis实现之字典跳跃表

    跳跃表 跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.跳跃表支持平均O(logN).最坏O(N)的时间复杂度查找,还可以通过顺序性操作来批量处理节 ...

  2. Apache shiro学习总结

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  3. 51、如何提取android代码中的字符串为系统资源文件 (I18N)

    工具:android studio 步骤1:找到要转为资源文件的字符串并选中,同时按下option+enter,弹出菜单,我们选中extract string resource 步骤2:在弹窗中输入你 ...

  4. 使用 Bullet,BulletManager 在 XNA 中创建子弹攻击目标(十五)

    平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛.在这里分享一下经验,仅为了和各位朋友交流经验.平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXN ...

  5. Python-S9-Day88——stark组件之设计urls

    03 stark组件之设计urls 04 stark组件之设计urls2 05 stark组件之设计list_display 06 stark组件之z查看页面的数据展示 03 stark组件之设计ur ...

  6. TopK-微博今日热门话题

    大纲 TopK on single node TopK on multiple nodes Realtime topK with low QPS Realtime topK with high QPS ...

  7. backpropagation算法示例

    backpropagation算法示例 下面举个例子,假设在某个mini-batch的有样本X和标签Y,其中\(X\in R^{m\times 2}, Y\in R^{m\times 1}\),现在有 ...

  8. hdu6134[莫比乌斯反演] 2017多校8

    /*hdu6134[莫比乌斯反演] 2017多校8*/ #include <bits/stdc++.h> using namespace std; typedef long long LL ...

  9. Java注解解析-搭建自己的注解处理器(CLASS注解使用篇)

    该文章是继Java注解解析-基础+运行时注解(RUNTIME)之后,使用注解处理器处理CLASS注解的文章.通过完整的Demo例子介绍整个注解处理器的搭建流程以及注意事项,你将知道如何去搭建自己的注解 ...

  10. 短文对话的神经反应机 -- Neural Responding Machine for Short-Text Conversation学习笔记

    最近学习了一篇ACL会议上的文章,讲的是做一个短文对话的神经反映机, 原文: 会议:ACL(2015) 文章条目:    Lifeng Shang, Zhengdong Lu, Hang Li: Ne ...