目录
去重的效率对比:(distinct + where)vs(group by + having)
having的使用
having :
step1:我们要把所有的信息都准备好,包括从关联表中获取需要的信息,
step2: 对数据集进行分组,形成一个包含所有需要的信息的数据集合。
step3: 接着,再通过 HAVING 条件的筛选,得到需要的数据
区别
区别1: 在关联查询中,WHERE 比 HAVING 更高效。
如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,HAVING 是先连接后筛选。
因此,在关联查询中,WHERE 比 HAVING 更高效。
因为,
-
WHERE 可以先筛选,用一个筛选后的较小数据集和关联表进行连接,这样占用的资源比较少,执行效率也就比较高。
-
HAVING 则需要先把结果集准备好,也就是用未被筛选的数据集进行关联,然后对这个大的数据集进行筛选,这样占用的资源就比较多,执行效率也较低。
区别2: 需要进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。
-
WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件;
-
HAVING 必须要与 GROUP BY 配合使用,可以把分组计算的函数和分组字段作为筛选条件。
因此,在需要对数据进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。
这是因为,在查询语法结构中:
-
WHERE 在 GROUP BY 之前,所以无法对分组结果进行筛选。(硬要进行分组查询的话,可能需要好几步,并把中间结果存储起来,再使用where进行筛选,或者干脆把这部分筛选功能放在应用层面,用代码来实现。但是,这样做的效率很低,而且会增加工作量,加大维护成本。所以,学会使用 HAVING,对你完成复杂的查询任务非常有帮助。)
-
HAVING 在 GROUP BY 之后,可以使用分组字段和分组中的计算函数,对分组的结果集进行筛选,这个功能是 WHERE 无法完成的。
合并使用
需要注意的是,WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。
我们可以把条件拆分开,
-
包含分组统计函数的条件用 HAVING,
-
普通条件用 WHERE。
这样,我们就既利用了 WHERE 条件的高效快速,又发挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。 当数据量特别大的时候,运行效率会有很大的差别。
HAVING后面需要使用聚合函数
Q:用 HAVING 查询单笔超过 50 元商品的 SQL 中,用到了 HAVING max(a.salesvalue)>50这个 max() 我不太理解,是指在分组后对每个组中的 salesvalue 取最大值再和 50 比较吗? 这块不明白导致后面原文说的“第三步,对分组后的数据集进行筛选,把组中字段“salesvalue”的最大值 >50 的组筛选出来。”就更不明白了。 我的疑问是,需求是找到比 50 大的就好,不理解这里为什么用到求最大值。求的是哪些数据范围的最大值呢?
A1:作者回复: 这里用max()的主要目的是,消除结果集中的重复记录。获得正确结果的方法不止一种,文中的查询主要是为了演示HAVING()的用法。
A2: 我的回复:我尝试了不加max 直接 having a.salesvalue>50, 会报错 1055。搜了一下,说是having后面要跟聚合函数——因为——having 的功能本来就是对 group by 分组后的数据进行第二次筛选的,所以 只能是一个聚合函数,否则会产生1对n的错误
A3:作者回复:HAVING后面的条件,必须是包含分组中计算函数的条件。这种说法是有道理的,主要是考虑到查询的效率。因为如果不是分组中的计算函数的条件,那么这个条件应该可以用WHERE而不是用HAVING,查询的效率就不高了
去重的效率对比:(distinct + where)vs(group by + having)
Q2: ===>MySQL distinct 与 group by 去重(where/having) - 李留广 - 博客园去重可以使用distinct,或者group by,两者效率如何对比?
-
联系前面的distinct,只是为了防止重复的话也可以用DISTINCT来替代。
-
那么想到了执行效率问题。搜到一篇文章(MySQL distinct 与 group by 去重(where/having) - 李留广 - 博客园) 说group by比distinct效率高一些。
-
但是在这个示例中 是用的(distinct +where) vs (group by+having ),where又比group by效率高一些,那么该如何判断这两个方案的效率呢?类似情况该依赖什么依据进行选择呢?
下面是两个方案的代码:
方案1 :distinct+where
select DISTINCT b.goodsname from transactiondetails as a join goodsmaster as b on a.itemnumber = b.itemnumber where a.salesvalue>50;
方案2 group by
select b.goodsname from transactiondetails as a join goodsmaster as b on a.itemnumber = b.itemnumber group by b.goodsname having max(a.salesvalue)>50;
sql语句的执行顺序会变化——mysql优化器
Q:sql语句的执行顺序,不是先执行join 再执行where吗?老师在提到where优点的时候说where的优点是先筛选在关联。这里似乎跟sql执行的顺序有了矛盾呢
A: 作者回复: mysql优化器在制定查询计划的时候,会对查询进行优化,比如重写查询语句,目的是提高查询的速度效率,不会机械按照固定的顺序执行。
1054报错
操作上来说: select 后面的字段如果不在group by分组内,会报错only_full_group_by的错,可以通过SELECT @@GLOBAL.sql_mode;查看全局参数,然后把only_full_group_by去掉,这样sql就不会报错了,但是还需要考虑这样执行出来的结果,是否正确。
业务逻辑上来说:既然分组,自然就会只用到分组字段和组内的计算,如果你还要用到其他字段,应该是你这个查询的需求还没有分析好。