志在巅峰的攀登者,不会陶醉在沿途的某个脚印之中。如下我这里有两张表,表t1为某活动的报名信息表,部分建表DDL如下表t2为投票信息表,也就是说t2表中保存的是给t1表中的报名用户投票记录信息,部分建表DDL如下:现在我t1表中有10条数据t2表中84条数据,如图所示现在有一需求就是查询户的投票记录以及报名信息,那么我们需要从t1表中获取报名信息,然后再从t2表中获取每个用户的投票记录。那么无非就是有两种查询思维,一种是先取t1,再循环取t2,另一种是使用join,那到底使用哪种,你是怎么决定的呢???1我们先来看看循环查询在不使用join的情况下,我们需要先从t1表中查出这用户的报名信息,然后循环从t2表中查询投票信息,这个过程如下执行select*fromt1,每一行数据记为C,这一步会对t1表进行全表扫描,我们t1表中是10条数据,全表扫描10行type=ALL,全表扫描,MYSQL扫描全表来找到匹配的行然后循环遍历这10行数据,从每一行数据C中取出字段id的值;执行select*fromt2whereactivity_user_id=id;(activity_user_id走的是索引树搜索)把返回的结果和C构成结果集的一行。在表t2中,满足t1表中id为12的有49条数据这个过程中扫描49行数据type=ref,使用非唯一性索引或者唯一索引的前缀扫描,返回匹配某个单独值的记录行。满足id为13的有35条数这个过程中扫描35行数据然后t1表中其他8条数据在表t2中没有记录,所以查询过程中各扫描一行。在这个过程中,这样查询下来,需要在业务代码中自己组装循环查询,t1表扫描10行,t2表扫描35+49+8=92,查询完成总共扫描行数据。2使用join时当使用join时,可以这样写:(使用STRAIGHT_JOIN保证固定联表顺序)满足条件的有84条数据这个语句的执行流程是这样的:第一步从表t1中读入一行数据C;第二步从数据行C中,取出id字段到表t2的activity_user_id索引树中搜索;第三步取出表t2中满足条件的行,跟C组成一行,作为结果集的一部分;第四步重复执行步骤1到3,直到表t1的末尾循环结束。这个过程是先遍历表t1,然后根据从表t1中取出的每行数据中的id值,去表t2中查找满足条件的记录,这个过程称为“IndexNested-LoopJoin”,简称NLJ。在这个过种中,t1表是驱动表,是走全表扫描,t2是被驱动表,是走树搜索,所以在join过程中,应该让小表作驱动表。此时我们将t2表中的activity_user_id索引删除我们再查询一下我们可以清楚的看到当不走索引搜索时,t1与t2都走了全表扫描,执行过程如下第一步扫描表t1,顺序读取数据行放入join_buffer中,假设放完第3行join_buffer满了,继续第二步操作;第二步扫描表t2,把t2中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回;第三步清空join_buffer;第四步继续扫描表t1,顺序读取最后的7行数据放入join_buffer中,继续执行第二步。这时候由于表t1被分成了两次放入join_buffer中,导致表t2会被扫描两次,这个过程就是“BlockNested-LoopJoin”。显然这两种情况“IndexNested-LoopJoin”与“BlockNested-LoopJoin”分析得出,如果可以使用到被驱动表中的索引,就可以使用join来查询。如果无法使用到被驱动表的索引查询,这样可能要扫描被驱动表很多次,会占用大量的系统资源,所以这种情况下join尽量不要用。完毕不局限于思维,不局限语言限制,才是编程的最高境界。
转载请注明:http://www.aierlanlan.com/rzfs/6004.html