SQL优化终于干掉了“distinct”

article/2025/9/18 4:53:00

SQL优化之多表联合查询干掉“distinct”去重关键字

  • 一、优化目的
  • 二、优化之前的sql长这样
  • 三、DISTINCT关键字的用法
  • 四、谈:如何优化distinct的sql
  • 五、distinct真的和group by等价吗?
  • 六、优化后的sql长啥样?
  • 七、总结
  • 2020.10.14更【来自评论区大佬的精彩观点】

一、优化目的

在我提交了代码的时候,架构师给我指出我这个sql这样写会有问题。因为在分库分表的时候,是不支持子查询的。

所以需要把多表的子查询的sql结构进行优化。

二、优化之前的sql长这样

是不是挺恐怖的;(此处为了脱敏,我把相关的sql关键词都给打码掉了)

在这里插入图片描述
这个sql的执行步骤如下:
1、查询出来d表中的某个id字段包含多个id值的所有的数据(因为此表是1-n的关系,所以需要去重,仅需要拿到不重复的id才可以继续下一个步骤);可以看到此步骤我把查询出来的多个值的结果给生成的了一个子表名为sss;

2、下一个步骤就是需要进行排序(以时间进行倒序排序,因为要在前台进行按时间进行展示);

3、第3步就是把这些结果与a表进行合并,查询出来排序后的每个id的信息;然后进行分页处理;

其他的可以不必关心,最终要的是去重关键字(DISTINCT),拿小本本记号,一会要考哦。

三、DISTINCT关键字的用法

实践是验证真理的唯一标准

例如有下表:

可以看到nameproduct_unit列有可能是重复的

mysql> SELECT t1.id,t1.name,t1.product_unit  FROM dd_product_category t1;
+----+----------+--------------+
| id | name     | product_unit |
+----+----------+--------------+
| 55 | 饮料     ||
| 56 | 饮料     ||
| 57 | 零食     ||
| 59 | 膨化食品 ||
| 60 | 方便食品 ||
| 61 | 自热火锅 ||
| 62 | 方便面   ||
| 63 | 矿泉水   ||
| 64 | 糖果     |              |
| 65 | 酒类     ||
| 66 | 烈酒     ||
| 67 | 啤酒     ||
| 68 | 预调酒   ||
+----+----------+--------------+
13 rows in set (0.13 sec)mysql> 
mysql> 

如何我们想只拿到name或者product_unit列的值并且不想要重复的值该怎么办?

1、拿到单个值是好拿的,但是是存在重复的数据的,这些重复的数据我们只保留一个就可以了,那么该怎么做呢?


mysql> SELECT t1.product_unit  FROM dd_product_category t1;
+--------------+
| product_unit |
+--------------+
||
||
||
||
||
||
||
||
|              |
||
||
||
||
+--------------+
13 rows in set (19.31 sec)mysql> 

2、去除重复列

mysql> 
mysql> SELECT DISTINCT t1.product_unit  FROM dd_product_category t1;
+--------------+
| product_unit |
+--------------+
||
||
||
||
||
|              |
+--------------+
6 rows in set (0.11 sec)mysql> 

是不是很简单,虽然看着简单,但是如果多表子查询的时候,就会出现问题,例如你想要查询表a,b,c三个表的数据,这三个表必然都是有关系的。

a和b是1-n的关系。但是你只有b表中id,你需要先查询出来b表的数据,然后利用b表的数据去查询a表的数据,然后再去查询c表的数据。

想必肯定是很绕的。

整个过程中你肯定是需要去重的

当整个sql写完,基本上跟我写的优化前的sql也就差不多了。(多表嵌套,多sql嵌套sql,啦啦啦一大堆)。

优化思路还是有很多的,当时能想到的就是把这个复杂的sql拆分成多个简单的sql执行,然后使用Java后台代码进行处理。(对于不甘于现状的我,想找到一个比这个更友好的解决方案的我,我是不会屈服这个问题的。

四、谈:如何优化distinct的sql

说到这里,先给大家放上一个链接:

  • 1、(Mysql5.7官方手册中提及到的关于优化distinct的方法)
    https://dev.mysql.com/doc/refman/5.7/en/distinct-optimization.html

  • 2、还有一个优化group by的:
    https://dev.mysql.com/doc/refman/5.7/en/group-by-optimization.html

推荐大家阅读。

Mysql5.7官方手册中提及到的关于优化distinct的方法,原文如下:

MySQL 5.7 Reference Manual / … / DISTINCT Optimization

8.2.1.16 DISTINCT Optimization

DISTINCT combined with ORDER BY needs a temporary table in many cases.

distinct 与order by 结合的许多情况下需要建一个临时表;

Because DISTINCT may use GROUP BY, learn how MySQL works with columns in ORDER BY or HAVING clauses that are not part of the selected columns. See Section 12.20.3, “MySQL Handling of GROUP BY”.

因为distinct可能使用group by,了解MySQL如何处理按order by 列或者具有不属于所选列的子句。见12.20.3节, “MySQL Handling of GROUP BY”.

In most cases, a DISTINCT clause can be considered as a special case of GROUP BY. For example, the following two queries are equivalent:

在大多数情况下,一个不同的子句可以被认为是group by 的特殊情况。例如下面这两个查询是等价的:

SELECT DISTINCT c1, c2, c3 FROM t1
WHERE c1 > const;
SELECT c1, c2, c3 FROM t1
WHERE c1 > const GROUP BY c1, c2, c3;

Due to this equivalence, the optimizations applicable to GROUP BY queries can be also applied to queries with a DISTINCT clause. Thus, for more details on the optimization possibilities for DISTINCT queries, see Section 8.2.1.15, “GROUP BY Optimization”.

由于这种等价性,适用于group by查询的优化,也可以应用于具有不同子句的查询。因此,关于distinct的查询优化的更多细节可以参考Section 8.2.1.15, “GROUP BY Optimization”.

When combining LIMIT row_count with DISTINCT, MySQL stops as soon as it finds row_count unique rows.

当row_count与distinct一起使用时,MySQL一旦发现row_count是唯一的行,就会停止。

If you do not use columns from all tables named in a query, MySQL stops scanning any unused tables as soon as it finds the first match. In the following case, assuming that t1 is used before t2 (which you can check with EXPLAIN), MySQL stops reading from t2 (for any particular row in t1) when it finds the first row in t2:

如果在查询中不适用来自所有表的列,MySQL一旦找到第一个匹配项就会停止扫描任何未使用的表。

在下面的例子中,假设t1在t2之前使用(你可以使用explanin来检查),MySQL在找到t2的第一行时停止从t2读取(对于t1中的任何特定行)。

SELECT DISTINCT t1.a FROM t1, t2 where t1.a=t2.a;

官方的手册中写到的,真是句句扣心呀!!!

总结有以下比较重要的几点:

  • 1、distinct与group by几乎等价;
  • 2、distinct的相关优化与group by的查询优化方法是等价的;

五、distinct真的和group by等价吗?

我们抱着试试看的态度,去做个试验。

就以下列这个效果为最终目的好了:

mysql> 
mysql> SELECT DISTINCT t1.product_unit  FROM dd_product_category t1;
+--------------+
| product_unit |
+--------------+
||
||
||
||
||
|              |
+--------------+
6 rows in set (0.11 sec)mysql> 

使用group by去重:

mysql> select  t1.product_unit from dd_product_category t1 group by t1.product_unit;
+--------------+
| product_unit |
+--------------+
|              |
||
||
||
||
||
+--------------+
6 rows in set (19.46 sec)mysql> 

可以看到,最终拿到的数据是一模一样的。

那么我们试验是成功的,distinct的效果和group by的效果是一样的。

那么我们优化distinct就变向的去优化group by了(我优化前的sql并未使用group by所以谈不上优化group by,只能说是把distinct的复杂sql改造成group by 的sql)。

打开我前面提到的这个优化group by的官方手册:
https://dev.mysql.com/doc/refman/5.7/en/group-by-optimization.html

由于原文比较长,这里就不在过多赘述。

现在需要做的就是把distinct改造成group by的sql语法的写法。

六、优化后的sql长啥样?

怎么样,改造后的sql,是不是还挺清爽的。

1、我们扔掉了多个嵌套sql

2、也不用去生成一个sss的临时表了

在这里插入图片描述

七、总结

对于本人而言学到了:

  • 1、distinct与group by几乎等价;
  • 2、distinct的相关优化与group by的查询优化方法是等价的;
  • 3、如果distinct的不能让sql最优化,那么可以尝试着使用group by的方式去改造一下。

这些我都上传到了百度云。
在这里插入图片描述

为了防止链接丢失可以关注公众号,回复:"mysql"。即可拿到MySQL相关的全部精彩内容。

欢迎一起学习,一起交流,一起进步。

关注我微信公众号第一时间推送给你精彩内容哦:

回复菜单,更有好礼,惊喜在等着你。

在这里插入图片描述

快来我粉丝群:每天欢快的玩耍(微信扫描二维码即可加入,群马上满,抓紧啦!!!)
在这里插入图片描述

2020.10.14更【来自评论区大佬的精彩观点】

感谢煎蛋没有蛋这位大佬提出的精彩观点

CSDN博客名:煎蛋没有蛋:

有distinct其实一方面也代表着表连接不到位或查询条件限制不到位或者是表结构设计不合理。

博主客气了,在传统的范式模型中,的确不应该出现这样的去重问题,你想取不重复的单位 应该有单位表;产品,应该有产品表,产品表中只有单位的id,取单位的名称直接查询单位表即可。但是在olap的场景下,现在都是拿空间换时间的,所以也有可能出现冗余字段的,只是从职业习惯上,一般看到需要去重的地方,都会回去扒拉下代码,看看是不是出了笛卡尔积。

附上大佬的博客地址:https://me.csdn.net/weixin_50666314,看得出来,是一位真大佬无疑了!


http://chatgpt.dhexx.cn/article/79PZCLBf.shtml

相关文章

SQL关于Date类型时间段查询优化(时间跨度稍长)(记一次自己工作开发中遇到的SQL优化经验)

前言 以下用于SQL查询的数据均为测试环境的数据,关键数据都已打码。 背景 我们的日常开放中都会遇到 查询某个时间段的数据,像这样: select * from test(表名) where time BETWEEN 2022-08-20 00:00:00 AND 2022-09-19 00:00:00但如果时间…

MySql基础知识总结(SQL优化篇)

🍅 作者简介:CSDN2021博客之星亚军🏆、新星计划导师✌、博客专家💪 🍅 哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师 🍅 关注公众号【哪吒编程】,回复1024&a…

【高级开发必掌握SQL】SQL优化篇

❤️作者主页:小虚竹 ❤️作者简介:大家好,我是小虚竹。Java领域优质创作者🏆,CSDN博客专家🏆,华为云享专家🏆,掘金年度人气作者🏆,阿里云专家博主&#x1f3…

SQL优化方案

转载至:http://blog.itpub.net/31555484/viewspace-2565387/ 作者1:惨绿少年 https://www.cnblogs.com/clsn/p/8214048.html 作者2:喜欢拿铁的人 https://zhuanlan.zhihu.com/p/49888088 在进行MySQL的优化之前,必须要了解的就是MySQL的查询过程&am…

慢SQL优化

1、慢查询统计 show VARIABLES like %que% SET GLOBAL slow_query_log on; //开启慢sql统计开关 SET GLOBAL long_query_time 1; //设置超过1秒则 认为是慢sql , 注意此处设置完之后需要重新链接客户端 才可以查看到设置成功 2、优化 索引优化 通过执行计划&…

Oracle数据库SQL优化详解

Oracle数据库SQL优化 1. Oracle SQL优化概述2. Oracle SQL优化详解2.1 Oracle 查询阻塞2.2 Oracle 查询耗时 SQL2.3.Oracle 查看执行计划2.4.Oracle 查看收集统计信息2.5.Oracle 查询优化器 -- 改写查询语句2.6.Oracle 查询优化器 -- 访问路径2.7.Oracle 查询优化器 -- 表连接方…

Mysql sql优化

这里引用深入Mysql实战 为什么要优化 提高资源利用率避免短板效应提高系统吞吐量同时满足更多用户的在线需求 简单来说,优化的目的是为了提高资源的利用率,让资源充分发挥价值。常见场景下,一台服务器有四大资源:cup、内存网络…

sql优化的15个小技巧

最近找了找怎么优化SQL,总结了15个基础技巧 因为最近一直在写sql的原因,所以需要知道sql该怎么优化,怕哪一天线上的接口,出了问题,需要优化,就需要采用改造成本最小的. 先上个导图 1.避免使用 select * 很多时候,我们写sql语句时,直接使用select *&am…

聊聊sql优化的15个小技巧

前言 sql优化是一个大家都比较关注的热门话题,无论你在面试,还是工作中,都很有可能会遇到。 如果某天你负责的某个线上接口,出现了性能问题,需要做优化。那么你首先想到的很有可能是优化sql语句,因为它的…

SQL优化的方法

(1)建立物化视图或尽可能减少多表查询。 (2)以不相干子查询替代相干子查询。 (3)只检索需要的列。 (4)用带in的条件子句等价替换or子句。 (5)经常提交com…

sql优化的N种方法_持续更新

当你访问网站的时候,有的时候会慢的想让你砸电脑,这个时候服务器要背锅了吗? 不,要背锅的不仅仅是服务器,数据库也有很大责任,不负责任的sql开发者更会让你崩溃的.为了提高sql响应速度,还是好好了解下sql的优化吧 sql优化的方式 一:sql性能分析 sql优化首先要对sql的消耗时…

sql优化常用的几种方法:19种最有效的sql优化技巧

我们来谈谈项目中常用的MySQL优化方法,共19条,具体如下: 1、EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看SQL执行计划。 下面来个简单的示例,标注(1、2、3、4、5)我们要重点关注的数据&#x…

sql优化的15个小技巧(必知五颗星),面试说出七八个就有了

目录 前言 1 避免使用select * 2 用union all代替union 3 小表驱动大表 4 批量操作 5 多用limit 6 in中值太多 7 增量查询 8 高效的分页 9 用连接查询代替子查询 10 join的表不宜过多 11 join时要注意 12 控制索引的数量 13 选择合理的字段类型 14 提升group by的…

MySQL高级篇(SQL优化、索引优化、锁机制、主从复制)

目录 0 存储引擎介绍1 SQL性能分析2 常见通用的JOIN查询SQL执行加载顺序七种JOIN写法 3 索引介绍3.1 索引是什么3.2 索引优劣势3.3 索引分类和建索引命令语句3.4 索引结构与检索原理3.5 哪些情况适合建索引3.6 哪些情况不适合建索引 4 性能分析4.1 性能分析前提知识4.2 Explain…

Sql优化总结!详细!(2021最新面试必问)

Sql优化 Sql执行顺序基础Sql优化查询SQL尽量不要使用select *,而是具体字段避免在where子句中使用or来连接条件使用varchar代替char尽量使用数值替代字符串类型查询尽量避免返回大量数据使用explain分析你SQL执行计划是否使用了索引及其扫描类型创建name字段的索引优…

如何破解VS2015(使用秘钥)

【时间】2018.10.07 【题目】如何破解VS2015(使用秘钥) 安装完vs2015 企业版/专业版后,在菜单帮助---注册产品,会显示产品试用期30天,怎么破解呢?其实只要输入相应的秘钥即可完成破解。如若不破解&#x…

vs2015激活码

microsoft visual studio2015是微软推出的一款集程序设计网页开发于一身的开发工具。microsoft visual studio 2015支持c,c,c#以及手机应用开发,用它所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows Mobile、Windows CE、.NET F…

VS2017 激活密钥

【时间】2018.11.26 【题目】VS2017 激活密钥 一、激活秘钥 Enterprise[企业版]: NJVYC-BMHX2-G77MM-4XJMR-6Q8QF Professional[专业版]: KBJFW-NXHK6-W4WJM-CRMQB-G3CDH 二、秘钥使用 使用位置在 帮助 -- 注册商品 中: 输入秘钥后,激活成功后&a…

Android APP性能测试以及性能指标

Android的app性能测试包括的测试项:Activity响应时间,帧率,内存,cpu消耗,耗电量,冷启动 Activity响应时间的相关测试 查看当前APP打开的页面命令: adb shell dumpsys activity | findstr mResumedActivity然后用命令去打开APP的某个activ…

APP性能测试之GT 测试

APP性能测试之GT 测试 1 什么是 GT GT(随身调)是腾讯研发的开源 APP 随身调测平台,它是直接运行在手机上的“集 成调测环境”(IDTE, Integrated Debug Environment)。 GT 仅凭一部手机,无需连接电脑&a…