1.用例子来说明最直观:
-
两张表t1(a字段有索引,100行数据),t2(a字段有索引,1000行数据)
-
使用
select * from t1 join t2 on(t1.a=t2.a);
来帮助我们分析在这个语句中,t1是驱动表,t2是被驱动表,t2字段a有索引,join过程中用上了这个索引
执行流程:
(1)从表t1中读入一行数据R
(2)从数据行R中,取出a字段到表t2中去查找
(3)取出表t2中满足条件的行,根R组成一行作为结果集的一部分
(4)重复执行步骤1到步骤3,直到t1鸟的末尾循环结束
-
对驱动表t1做了全表扫描,这个过程需要扫描100行,而对于每一行的R,根据字段a去表t2中查找,
走的是树搜索过程,也会扫描100行,整个流程总扫描行数是200。
能不能使用join?
使用单表查询:
(1)select * from t1;
查出表t1的所有数据,有100行。
(2)循环遍历100行数据;
从每一行取出字段a的值$R.a;
执行select * from t2 where a=$R.a;
把返回的结果和R构成结果集的一行。
这个过程也是扫描了200行,但共执行了101条语句,比直接join多了100次交互,除此之外,客户端还要自己拼接结果。 显然单表查询不如直接join好!!!
2.怎么选择驱动表?
在join语句执行过程中,驱动表走的是全表扫描,被驱动表走的是树搜索。
假设被驱动表的行数是M,每次在驱动被驱动表查一行数据,要先搜索索引a,再搜索主键索引。每次搜索一棵树的近似复杂度是以2为底的M的对数,总共的时间复杂度为:2*log2M。
假设驱动表的行数是N,执行过程中要扫描N次,对于每一行就要到被驱动表上匹配一次。
整个过程的近似复杂度是N+N*2*log2M,显然N对扫描行数的影响更大。
应该让小表做驱动表!!!
3.总结(前提是可以使用上被驱动表的索引)
-
使用join语句,性能比强行拆成多个单表执行SQL语句的性能要好
-
如果使用join语句的话,需要让小表做驱动表
-
若join语句用不上被驱动表的索引,则不要使用join
小表是参与计算join的各个字段的总数据量,那个数据量小,那个就是小表