连表查询的优化思路

问题

1、如下图,虽然图中的type,有个表没用到索引,但是这个表数据很小,才被检索了115条数据,而最多的那张表也只被检索了2108条数据,而且还用上索引了,但是这条sql执行了298s,如何优化

解决方案

1、给那个没用到索引的数据表加索引

原理

这里就涉及到连表查的时候会用到的算法,笛卡尔积

顾名思义, 这个概念得名于笛卡儿. 在数学中,两个集合 X 和 Y 的笛卡儿积(Cartesian product),又称直积,表示为 X × Y,是其第一个对象是 X 的成员和第二个对象是 Y 的一个成员的所有可能的有序对.

假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以扩展到多个集合的情况。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。

也就是说,当我们连表的时候,数据库会把我们两张表 on 条件下的所有可能性都给列出来,所以上图中看似只是检索了2108和115,但是其实组合的可能性是 2108的115次方,然后从这些数据里再进行where 条件的检索,所以我们的目标是,尽可能减少每个连表所检索的条数,即使看似几千条数据,相乘之后便是几十亿的数据量了

不过在连表查中,虽然有笛卡尔积,但是也会根据 on 后面的条件先一步来筛选数据,而不是直接将连表的检索数据进行笛卡尔积

2、将where里的条件提前

比如一条sql如下

select p.*, a.* from pay as p left join account a on p.uid=a.id where p.time between '2020-03-15 00:00:00' and '2020-03-20 00:00:00' and a.uid between 1000 and 30000 group by a.uid order by p.time desc

上面sql说的是,一张储值表 pay,一张用户表account,连表查这两张表,将储值时间在2020-03-15 00:00:00 到 2020-03-20 00:00:00 且 用户uid在 1000 到 30000 的数据拿出来,然后根据用户来分组

首先我们看看mysql会怎么执行这条sql,具体文档路径是 https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008/ms189499(v=sql.100)?redirectedfrom=MSDN

我就直接摘出来了

1、执行from后面的,也就是先连上pay这张表

2、然后是on,也就是p.uid=a.id 先把这个过滤条件记上,如果有索引,就加载索引

3、然后是join,也就是连上 account这张表,如果sql是好几张表,就连上好几张表,这时候加上2的条件,就初步筛选出来一部分数据,这里会使用笛卡尔积,这里如果pay表和account表很大,那这部分数据筛出来也是会很庞大也会耗时

4、然后是where,从3中进一步筛选,有索引的话会更快

5、然后是group by

6、最后是order by

从上面步骤就知道第3步,事实上我们是不需要先把pay表和account都匹配一遍的,所以,如果我们使用子查询把where条件提前,就能避免这个问题

sql修改如下

select p.*, a* from (select * from payment where time between '2020-03-15 00:00:00' and '2020-03-20 00:00:00') as p left join (select * from account where uid between 1000 and 30000) as a on p.uid=a.id group by a.uid order by p.time

因为mysql会先执行子查询,在子查询中,payment表和account表已经被过滤了好多数据量,然后再进行主查询,这样就能把时间降下来

通过这个修改,上面我遇到的sql耗时问题,在我还没给表加索引的情况下,执行时间已经从298s降到了11s,估计加上索引还会更快

mysql执行一条sql的顺序

Processing Order of the SELECT statement
The following steps show the processing order for a SELECT statement.

1.FROM

2.ON

3.JOIN

4.WHERE

5.GROUP BY

6.WITH CUBE or WITH ROLLUP

7.HAVING

8.SELECT

9.DISTINCT

10.ORDER BY

11.TOP

你可能感兴趣的:(数据库)