原文出处:

https://blog.csdn.net/u010745238/article/details/42846897

http://blog.sina.com.cn/s/blog_5017ea6c0101e3c4.html

https://www.cnblogs.com/zox2011/archive/2012/09/12/2681797.html

尽量不要使用 distinct

大多数情况下,Distinct函数都会导致对最终结果集完成一次排序,因此,这就成为成本最昂贵的排序之一。Distinct一直是SQL语言中成本最高的函数之一。不过,对于DB2V9,优化工具会尽量利用索引来消除为确定唯一性所带来的排序,其方法类似于目前用GroupBy语句完成优化时的做法。不过,实际上不必在SQL中使用Distinct,完全可以使用其他方式重写查询来得到同样的结果,这样做往往更为高效。开发人员现在都很喜欢用Distinct,很多人在所有语句上都会加上Distinct来确保不出现重复。不过这种代码的效率很低。在对应用调优时,我首先要做的事情之一就是审查源代码,找出所有包含Distinct的语句,了解这些查询是否确实会得到重复的结果,查看这个Distinct是否会导致一个排序,然后重写这些语句。通过对每晚批量作业的全面分析,就能很容易地大幅减少批量处理周期时间。不过要记住,如果查询中包含Distinct,只要不会因此导致执行一个排序,这个查询可能也很高效。

要从结果集消除重复,可以尝试下面的做法:

使用GroupBy(V9之前),这会利用关联索引来消除为确定唯一性所导致的排序。

使用一个In或Exists子查询重写查询。如果某个表可能导致重复(由于是一对多关系),但是这个表中并不包含结果集将返回的数据,这种情况下这种方法就很适用。

例如,给定当前参与项目的一组员工。其中很多员工可能同时参加了多个项目,不过我们希望他们只出现一次。以下查询:

SELECTDISTINCTE.EMPNO,E.LASTNAME

FROMEMPE,

EMPPROJACTEP

WHEREE.EMPNO=EP.EMPNO

可以重写为:

SELECTE.EMPNO,E.LASTNAME

FROMEMPE,

EMPPROJACTEP

WHEREE.EMPNO=EP.EMPNO

GROUPBYE.EMPNO,E.LASTNAME

也可以重写为:

SELECTE.EMPNO,E.LASTNAME

FROMEMPE

WHEREEXISTS

(SELECT1

FROMEMPPROJACTEP

WHEREE.EMPNO=EP.EMPNO)

还可以重写为:

SELECTE.EMPNO,E.LASTNAME

FROMEMPE

WHEREE.EMPNOIN

(SELECTEP.EMPNO

FROMEMPPROJACTEP)

用EXISTS替换DISTINCT ,提高效率

用EXISTS替换DISTINCT: 当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换, EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.尽量使用exists而不是distinct,因为distinct在禁止重复行之前要排序检索到的行。

例子:

(低效):

SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E WHERE D.DEPT_NO = E.DEPT_NO

(高效):

SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X' FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);

用EXISTS的确可以替代DISTINCT,不过以上方案仅适合DEPT_NO为唯一主键的情况。 如果要去掉重复记录,需参照以下方法:

SELECT * FROM EMP WHERE DEPT_NO EXISTS(select Max(DEPT_NO) FROM DEPT D , EMP E WHERE E.DEPT_NO = D.DEPT_NO GROUP BY D.DEPT_NO)

得到重复记录数

SELECT * FROM EMP WHERE DEPT_NO NOT EXISTS(select Max(DEPT_NO) FROM DEPT D , EMP E WHERE E.DEPT_NO = D.DEPT_NO GROUP BY D.DEPT_NO)

MySQL中distinct和group by性能比较

之前看了网上的一些测试,感觉不是很准确,今天亲自测试了一番。得出了结论(仅在个人计算机上测试,可能不全面,仅供参考)

测试过程:

准备一张测试表

1    CREATE TABLE `test_test` (
2      `id` int(11) NOT NULL auto_increment,
3      `num` int(11) NOT NULL default '0',
4      PRIMARY KEY  (`id`)
5     ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

建个储存过程向表中插入10W条数据

01    create procedure p_test(pa int(11))
02     begin
03
04      declare max_num int(11) default 100000;
05      declare i int default 0;
06      declare rand_num int;
07
08      select count(id) into max_num from test_test;
09
10      while i < pa do
11              if max_num < 100000 then
12                      select cast(rand()*100 as unsigned) into rand_num;
13                      insert into test_test(num)values(rand_num);
14              end if;
15              set i = i +1;
16      end while;
17     end

调用存储过程插入数据

1    call p_test(100000);

开始测试:(不加索引)

01    select distinct num from test_test;
02    select num from test_test group by num;
03
04    [SQL] select distinct num from test_test;
05    受影响的行: 0
06    时间: 0.078ms
07
08    [SQL]
09    select num from test_test group by num;
10    受影响的行: 0
11    时间: 0.031ms

二、num字段上创建索引

1    ALTER TABLE `test_test` ADD INDEX `num_index` (`num`) ;

再次查询

01    select distinct num from test_test;
02    select num from test_test group by num;
03    [SQL] select distinct num from test_test;
04    受影响的行: 0
05    时间: 0.000ms
06
07    [SQL]
08    select num from test_test group by num;
09    受影响的行: 0
10    时间: 0.000ms

这时候我们发现时间太小了 0.000秒都无法精确了。

我们转到命令行下 测试

01    mysql> set profiling=1;
02    mysql> select distinct(num) from test_test;
03    mysql> select num from test_test group by num;
04    mysql> show profiles;
05    +----------+------------+----------------------------------------+
06    | Query_ID | Duration   | Query                                  |
07    +----------+------------+----------------------------------------+
08    |        1 | 0.00072550 | select distinct(num) from test_test    |
09    |        2 | 0.00071650 | select num from test_test group by num |
10    +----------+------------+----------------------------------------+

加了索引之后 distinct 比没加索引的 distinct 快了 107倍。

加了索引之后 group by 比没加索引的 group by 快了 43倍。

再来对比 :distinct  和 group by

不管是加不加索引 group by 都比 distinct 快。因此使用的时候建议选 group by

收集了一些distinct性能相关的文章 希望有用相关推荐

  1. 收集的SQL Server性能相关资料

    这是本人在工作中整理的关于SQL Server性能相关资料,便于随时查阅 目录 性能监视器指标 内存问题诊断 侦测 CPU 压力 磁盘相关 内存 Memory Clerks Buffer Pool P ...

  2. 该系列主要整理收集在使用C#开发WinForm应用文章及相关代码来源于WinForms小组...

    该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm ...

  3. 如何收集常见的前端性能信息

    前端性能指标,大多有TTFB ,首屏,首次可交互时间等 相关的文章已经有很多,细节这里就不多说了,可参考文末资料 总体来说,需要知道浏览器(新的)给我们提供了 Performance API,使用这个 ...

  4. Oracle 性能相关常用脚本(SQL)

    在缺乏的可视化工具来监控数据库性能的情形下,常用的脚本就派上用场了,下面提供几个关于Oracle性能相关的脚本供大家参考.以下脚本均在Oracle 10g测试通过,Oracle 11g可能要做相应调整 ...

  5. 2019年上半年收集到的人工智能机器学习方向干货文章

    2019年上半年收集到的人工智能机器学习方向干货文章 10种机器学习方法,掌握了就可以称霸朋友圈 人工智能常见算法简介 机器学习中的最优化算法总结 最萌算法学习来啦,看不懂才怪! The Next S ...

  6. 2019年上半年收集到的人工智能卷积神经网络干货文章

    2019年上半年收集到的人工智能卷积神经网络干货文章 了解CNN这一篇就够了--关于卷积神经网络的介绍 关于卷积的6个基本知识 一文读懂深度学习中的各种卷积 CNN卷积神经网络的三种基本模式(不懂的话 ...

  7. 2019年上半年收集到的人工智能图神经网络干货文章

    2019年上半年收集到的人工智能图神经网络干货文章 「AI初识境」从头理解神经网络-内行与外行的分水岭 人工智能中"图神经网络GNN"如何理解?(附斯坦福综述) 清华大学图神经网络 ...

  8. 2019年上半年收集到的人工智能开源框架介绍文章

    2019年上半年收集到的人工智能开源框架介绍文章 TensorFlow基本使用 TensorFlow.js:让你在浏览器中也能玩转机器学习 人工智能学习框架TensorFlow渐近分析 TensorF ...

  9. python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)...

    ################################################################## # PUBLIC METHODS THAT ALTER ATTRI ...

最新文章

  1. 把java程序作为windows服务运行
  2. IntelliJ IDEA创建web项目及异常问题解决
  3. apache karaf_未来是Apache Karaf上的微服务架构
  4. Python分布式爬虫打造搜索引擎(三)
  5. web文件操作常见安全漏洞(目录、文件名检测漏洞)
  6. python笔记-动态类型
  7. Jmeter及JDK下载安装配置教程
  8. mac更新完后读取不出移动硬盘的问题解决
  9. [5-20]绿色精品软件每天更新[uc23整理]
  10. 14届数独-真题标准数独-Day 1-20220116
  11. 使用postman发送post请求下载文件
  12. 大数据常用web页面
  13. 一锄落花,葬在了寂寞的天涯
  14. Take me to your heart 《吻别》英文版 已配了歌词
  15. LTE网络CQI机制
  16. node.js毕业设计鲸落图书商城小程序LW(源码+程序+LW+部署)
  17. 面试-操作系统-进程管理-进程-进程调度-死锁
  18. 百度地图如何去除 百度地图的logo
  19. fill()的使用方法
  20. CheckListBox的一些用法!

热门文章

  1. 学习前端,需要掌握的单词集汇总
  2. 蓝牙电子秤方案_IC/PCBA
  3. 外贸鞋店瞄上中高端小区
  4. 20190912-1 每周例行报告
  5. 数据库查询和数据操纵
  6. gridControl自动增加行添加数据
  7. 基于微信在线教育视频学习小程序毕业设计毕设作品(2)小程序功能
  8. gsm模块网站服务器,GPRS模块与GSM模块的七大区别
  9. Java程序设计——事务管理(JDBC编程)
  10. 实时法线贴图dxt压缩算法