在项目中的某个查询由于设计了多表查询,前端发送的某个接口到收到数据经历了很长时间,所以决定来优化一下这个查询。
首先一张驱动表students表有2000多条数据
被驱动表course有5800条数据左右
下面students和course表的简称分别为p和pic,
首先,我们尝试了一下where后面条件的等值连接
结果出乎我们的意料,结果是不对的,少了很多数据。
我们的结果是要求所有的学生记录都需要,但是由于等值连接(内连接)的过程,所以出错了。
一方面,由于数据库对于这种没有主表要求的具体sql来说,是会有它自己的优化过程,它会选取一个最优的查询结果。 那就把我们认为是被驱动表的表当成驱动表也就是主表在使用了,因为我们的p表的p_id是主键,它是有聚簇索引的,对于聚簇索引,其本质上就是一颗b+树,可以根据具体的值快速找到所需要的数据,聚簇索引与非聚簇索引的区别在于是否需要所谓的“回表”的过程,所以数据库就出现了以p表为被驱动表的样子,使得结果不是需要的结果。
另一方面,对于上面这条sql来说,p表的主键是p_id,而pic表的主键是pc_id,除了聚簇索引外两表再无其它索引,where可能就会出现错误的结果,如果pic表表的某些数据没有对应的p表数据 那么结果中不出现,如果p表中的数据没有在pic表中对应出现 那么结果中也不会出现内连接(Inner join on)和等值连接(where ) 其实是一样的。
对于这个sql我们应该让p表进行 left join表pic表
对于这个没有索引的sql,且sql明确指出p表为主表,其查询过程如上图所示,其实是对p表进行 nested loop join,拿着p表的每一条数据进行与pic表的每一条数据进行比对,如果join的表的对应字段没有索引,那么就会出现被驱动表全表扫描的过程,这个时间的开销是很大的。
接下来我们给pic表的p_id加入索引后,这个索引是普通索引,也就是非聚簇索引,会有回表的过程,
加入索引后的时间下降了4倍多一些。