在 MySQL 查询中,可能会包含重复值。这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值。

关键词 DISTINCT 用于返回唯一不同的值,就是去重啦。用法也很简单: SELECT DISTINCT * FROM tableName

DISTINCT 这个关键字来过滤掉多余的重复记录只保留一条。

另外,如果要对某个字段去重,可以试下: SELECT *, COUNT(DISTINCT nowamagic) FROM table GROUP BY nowamagic

这个用法,MySQL的版本不能太低。

在编写查询之前,我们甚至应该对过滤条件进行排序,真正高效的条件(可能有多个,涉到同的表)是查询的主要驱动力,低效条件只起辅助作用。那么定义高效过滤条件的准则是什呢?首先,要看过滤条件能否尽快减少必须处理的数据量。所以,我们必须倍加关注条件的写方式。

假设有四个表: customers 、 orders 、 orderdetail 、 articles ,现在假设 SQL 要处理的问题是:找出最近六个月内居住在 Gotham 市、订购了蝙蝠车的所有客户。当然,编写这个查询有多种方法, ANSI SQL 的推崇者可能写出下列语句: select distinct c.custname

from customers c

join orders o

on o.custid = c.custid

join orderdetail od

on od.ordid = o.ordid

join articles a

on a.artid = od.artid

where c.city = 'GOTHAM'

and a.artname = 'BATMOBILE'

and o.ordered >= somefunc

其中, somefunc 是个函数,返回距今六个月前的具体日期。注意上面用了 distinct ,因为考虑到某个客户可以是大买家,最近订购了好几台蝙蝠车。

暂不考虑优化器将如何改写此查询,我们先看一下这段代码的含义。首先,来自 customers 表的数据应只保留城市名为 Gotham 的记录。接着,搜索 orders 表,这意味着 custid 字段最好有索引,否则只有通过排序、合并或扫描 orders 表建立一个哈希表才能保证查询速度。对 orders 表 ,还要针对订单日期进行过滤:如果优化器比较聪明,它会在连接( join )前先过滤掉一些数据,从而减少后面要处理的数据量;不太聪明的优化器则可能会先做连接,再作过滤,这时在连接中指定过滤条件利于提高性能,例如: join orders o

on o.custid = c.custid

and a.ordered >= somefunc

注意,如果是: left outer join orders o on

o.custid = c.custid

and a.ordered >= somefunc

此处关于left表的筛选条件将失效,因为是左外连接,左表的所有列都将出现在这次连接结果集中)。

即使过滤条件与连接( join )无关,优化器也会受到过滤条件的影响。例如,若 orderdetail 的主键为( ordid, artid ),即 ordid 为索引的第一个属性,那么我们可以利用索引找到与订单相关的记录。但如果主键是( artid, ordid )就太不幸了(注意,就关系理论而言 ,无论哪个版本都是完全一样),此时的访问效率比( ordid, artid )作为索引时要差,甚至一些数据库产品无法使用该索引(注 3 ),唯一的希望就是在ordid 上加独立索引了。

连接了表 orderdetail 和 orders 之后,来看 articles 表,这不会有问题,因为表 order 包括 artid 字段。最后,检查 articles 中的值是否为 Batmobile 。查询就这样结束了,因为用了 distinct ,通过层层筛选的客户名还必须要排序,以剔除重复项目。

避免在最高层使用 distinct 应该是一条基本规则 。原因在于,即使我们遗漏了连接的某个条件, distinct 也会使查询 " 看似正确 " 地执行 —— 无可否认,发现重复数据容易,发现数据不准确很难,所以避免在最高层使用 distinct 应该是一条基本规则。

发现结果不正确更难,例如,如果恰巧有多位客户都叫 " Wayne " , distinct 不但会剔除由同个客户的多张订单产生的重复项目,也会剔除由名字相同的不同客户产生的重复项目。事实上,应该同时返回具唯一性的客户 ID 和客户名,以保证得到蝙蝠车买家的完整清单。

要摆脱 distinct ,可考虑以下思路:客户在 Gohtam 市,而且满足存在性测试,即在最近六个月订购过蝙蝠车。注意,多数(但非全部) SQL 方言支持以下语法: select c.custname

from customers c

where c.city = 'GOTHAM'

and exists (select null

from orders o,

orderdetail od,

articles a

where a.artname = 'BATMOBILE'

and a.artid = od.artid

and od.ordid = o.ordid

and o.custid = c.custid

and o.ordered >= somefunc )

上例的存在性测试,同一个名字可能出现多次,但每个客户只出现一次,不管他有多少订单。有人认为我对 ANSI SQL 语法的挑剔有点苛刻(指 " 蝙蝠车买主 " 的例子),因为上面代码中customers 表的地位并没有降低。其实,关键区别在于,新查询中 customers 表是查询结果的唯一来源(嵌套的子查询会负责找出客户子集),而先前的查询却用了 join 。

这个嵌套的子查询与外层的 select 关系十分密切。如代码第 11 行所示(粗体部分),子查询参照了外层查询的当前记录,因此,内层子查询就是所谓的关联子查询( correlated subquery )。

此类子查询有个弱点,它无法在确定当前客户之前执行。如果优化器不改写此查询,就必须先找出每个客户,然后逐一检查是否满足存在性测试,当来自 Gotham 市的客户非常少时执行效率倒是很高,否则情况会很糟(此时,优秀的优化器应尝试其他执行查询的方式)。 select custname

from customers

where city = 'GOTHAM'

and custid in

(select o.custid

from orders o,

orderdetail od,

articles a

where a.artname = 'BATMOBILE'

and a.artid = od.artid

and od.ordid = o.ordid

and o.ordered >= somefunc)

在这个例子中,内层查询不再依赖外层查询,它已变成了非关联子查询( uncorrelated subquery ),只须执行一次。很显然,这段代码采用了原有的执行流程。在本节的前一个例子 中 ,必须先搜寻符合地点条件的客户(如均来自 GOTHAM ),接着依次检查各个订单。而现在,订购了蝙蝠车的客户,可以通过内层查询获得。

不过,如果更仔细地分析一下,前后两个版本的代码还有些更微妙的差异。含关联子查询的代码中,至关重要的是 orders 表中的 custid 字段要有索引,而这对另一段代码并不重要,因为这时要用到的索引(如果有的话)是表 customers 的主键索引。

你或许注意到,新版的查询中执行了隐式的 distinct 。的确,由于连接操作,子查询可能会返回有关一个客户的多条记录。但重复项目不会有影响,因为 in 条件只检查该项目是否出现在子查询返回的列表中,且 in 不在乎某值在列表中出现了一次还是一百次。但为了一致性,作为整体,应该对子查询和主查询应用相同的规则,也就是在子查询中也加入存在性测试: select custname

from customers

where city = 'GOTHAM'

and custid in

(select o.custid

from orders o

where o.ordered >= somefunc

and exists (select null

from orderdetail od,

articles a

where a.artname = 'BATMOBILE'

and a.artid = od.artid

and od.ordid = o.ordid))

或者 select custname

from customers

where city = 'GOTHAM'

and custid in

(select custid

from orders

where ordered >= somefunc

and ordid in (select od.ordid

from orderdetail od,

articles a

where a.artname = 'BATMOBILE'

and a.artid = od.artid)

尽管嵌套变得更深、也更难懂了,但子查询内应选择 exists 还是 in 的选择规则相同:此选择取决于日期与商品条件的有效性。除非过去六个月的生意非常清淡,否则商品名称应为最有效的过滤条件,因此子查询中用 in 比 exists 好,这是因为,先找出所有蝙蝠车的订单、再检查销售是否发生在最近六个月,比反过来操作要快。如果表 orderdetail 的 artid 字段有索引,这个方法会更快,否则,这个聪明巧妙的举措就会黯然失色。

每当对大量记录做存在性检查时,选择 in 还是 exists 须斟酌。

利于多数 SQL 方言,非关联子查询可以被改写成 from 子句中的内嵌视图。然而,一定要记住的是, in 会隐式地剔除重复项目,当子查询改写为 from 子句中的内嵌视图时,必须要显式地消除重复项目。例如: select custname

from customers

where city = 'GOTHAM'

and custid in

(select o.custid

from orders o,

(select distinct od.ordid

from orderdetail od,

articles a

where a.artname = 'BATMOBILE'

and a.artid = od.artid) x

where o.ordered >= somefunc

and x.ordid = o.ordid)

总结:保证 SQL 语句返回正确结果,只是建立最佳 SQL 语句的第一步。

mysql去重复查询 性能_MySQL中distinct语句去查询重复记录及相关的性能讨论相关推荐

  1. mysql去重复查询 性能_MySQL中distinct语句去查询重复记录及相关的性能讨论_MySQL...

    在 MySQL 查询中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值,就是去重啦.用法也很简单: SELE ...

  2. mysql 重复数据 distinct_MySQL中distinct语句去查询重复记录及相关的性能讨论

    在 MySQL 查询中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值,就是去重啦.用法也很简单: SELE ...

  3. distinct mysql性能_MySQL中distinct与group by之间的性能进行比较

    最近在网上看到了一些测试,感觉不是很准确,今天亲自测试了一番.得出了结论,测试过程在个人计算机上,可能不够全面,仅供参考. 测试过程: 准备一张测试表 CREATE TABLE `test_test` ...

  4. distinct mysql性能_MySQL中distinct和group by性能比较

    MySQL中distinct和group by性能比较[转] 之前看了网上的一些测试,感觉不是很准确,今天亲自测试了一番.得出了结论(仅在个人计算机上测试,可能不全面,仅供参考) 测试过程: 准备一张 ...

  5. mysql教程or怎么用_MySQL中or语句用法示例

    1.mysql中or语法的使用,在mysql语法中or使用注意点. 项目遇到坑,遍历发放奖励数据查询错误!!! $sql = 'SELECT * FROM `vvt_spread_doubleegg_ ...

  6. mysql数据库 or的用法_MySQL中or语句用法示例

    1.mysql中or语法的使用,在mysql语法中or使用注意点. 项目遇到坑,遍历发放奖励数据查询错误!!! $sql = 'SELECT * FROM `vvt_spread_doubleegg_ ...

  7. mysql查询重复的名字_Mysql中like用法:查询名字中含有风字的学生信息

    一.表名和字段 –1. 学生表 student (s_id,s_name,s_birth,s_sex) –学生编号,学生姓名,出生年月,学生性别 –2. 课程表 course (c_id,c_name ...

  8. mysql临时关闭索引功能_MYSQL中常用的强制性操作(例如强制索引)

    mysql常用的hint 对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法.同样,在mysql里,也有类似的hint功能.下面介绍一些常用的 ...

  9. mysql的force的作用_mysql中force Index等一些不是很常用的sql优化介绍

    oracle的hint功能种类很多,对于优化sql语句提供了很多方法. 在mysql里,也有类似的hint功能. 下面为大家介绍一些比较常用的,供大家学习参考. 1.强制索引 FORCE INDEX ...

最新文章

  1. Deno 兼容浏览器具体指的是什么?
  2. Vmware workstation 网络连接类型
  3. SAP项目MM调研清单
  4. iOS 13 绕过锁屏密码查看通讯录、照片、短信
  5. mysql拒绝访问root用户_Linux部署MySql数据库(超简单)
  6. 支持向量机smo matlab,理解支持向量机(三)SMO算法
  7. nodeName、nodeValue 以及 nodeType 包含有关于节点的信息
  8. win7安装android驱动,Windows7:安卓智能手机刷机驱动安装教程(图文详解)
  9. 12864液晶显示c语言程序,单片机+lcd12864液晶万年历C程序
  10. WORD图片打印预览没有
  11. 怎么把好几行弄成一行_怎么在word文档里把很多行一下合并成一行
  12. Windows Server 2016 NTP服务端和客户端配置
  13. 开发一个Android志愿填报系统(后台管理+前台app)毕业设计
  14. GitHub如何征服了Google、微软及一切
  15. 网络安全从业人员应具备的职业素养
  16. 【工作日记】这一年来完全用Linux工作的感受
  17. MyBatisPlus:实现DAO的增删改查分页+属性设置,代码生成器(代码模板)
  18. SuperSet (真)完全汉化
  19. STC硬件主板--电子乐谱展示的设计
  20. 你需要启用steam社区界面功能以进行购买_GTA5OL:名钻赌场豪劫新手如何购买与安装图文教程...

热门文章

  1. android端口数据包,【图片】android抓包工具fiddler抓包使用方法 跟踪监控android数据包【中国红客联盟吧】_百度贴吧...
  2. 【微软漏洞分析】MS15-023 Win32k 特权提升漏洞 - CVE-2015-0078 + 绕过(CVE-2015-2527 in MS15-097)
  3. js语音播报功能(1)
  4. 2021-01-19古文观止赏析
  5. JavaScript向页面输出内容的四种方法
  6. 诺基亚n1系统更新显示无网络_2G即将退网,备用机和老人机该升级诺基亚4G功能机了...
  7. Python的制表符和运算符
  8. DNF登陆的时候说连接服务器失败,请检查您的网络。是否启用修复程序进行修复?,地下城和勇士常见问题修复方法.doc...
  9. 使用JavaScript制作动态网页-1
  10. 加微信/转微博,赢华章经典计算机图书