一、优化目标
在我提交了代码的时候,架构师给我指出我这个sql这样写会有问题。因为在分库分表的时候,是不反对子查问的。
所以须要把多表的子查问的sql构造进行优化。
二、优化之前的sql长这样
是不是挺恐怖的;(此处为了脱敏,我把相干的sql关键词都给打码掉了)
这个sql的执行步骤如下:
1、查问进去d表中的某个id字段蕴含多个id值的所有的数据(因为此表是1-n的关系,所以须要去重,仅须要拿到不反复的id才能够持续下一个步骤);能够看到此步骤我把查问进去的多个值的后果给生成的了一个子表名为sss;
2、下一个步骤就是须要进行排序(以工夫进行倒序排序,因为要在前台进行按工夫进行展现);
3、第3步就是把这些后果与a表进行合并,查问进去排序后的每个id的信息;而后进行分页解决;
其余的能够不用关怀,最终要的是去重关键字(DISTINCT),拿小本本记号,一会要考哦。
三、DISTINCT关键字的用法
实际是验证真谛的唯一标准
例如有下表:
能够看到name
和product_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 t1WHERE c1 > const;
SELECT c1, c2, c3 FROM t1WHERE 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的形式去革新一下。