语法
- ... from tb1 join(inner join) tb2 on condition
- ... from tb1 left join tb2 on condition
- ... from tb1 right join tb2 on condition
- ... from tb1 full join tb2 on condition【1】
阿里巴巴Java开发手册
【强制】 超过三个表禁止join。需要join的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。
说明 : 即使双表join也要注意表索引、SQL性能。【2】
为什么对join进行限制?join的过程是怎样的?
现在假设有两个表tb1和tb2,都有字段id、a、b,id为主键,a上有索引,tb1中有100行数据,tb2中有1000行数据。【3】
explain ... tb1 join tb2 on tb1.a = tb2.a
会发现tb1是全表扫描,tb2是走的索引,这很好理解相当于两层for,只是第二层可以通过所以找到想找的值。具体过程为依次从tb1中读一行,再去通过索引找tb2中满足条件的行。explain ... tb1 join tb2 on tb1.a = tb2.b
因为没有索引,这就是两层for了,显然时间复杂度是不可接受的,因此MySQL的做法是这样:- 将tb1放到join_buffer中(当然这里也可能出现放不下的情况)
- 全表扫描tb2,然后与join_buffer中的数据进行比较找到满足条件的行(这个专栏其实没有讨论tb2放不下的情况,待补充)。这里举个例子说明一下为什么可以加快速度,假设tb1需要分5次才能放到join_buffer中,对于其中的一次来说,将tb1的1/5放入到join_buffer中,再对tb2全表扫描,接着对比tb1和tb2找到满足条件的行,而这样的操作需要5次才能完成,也就是说tb2有5次的全表扫描,若采用类似于两层for的方式的话需要:5 * join_buffer中的大小(前提是第5次也正好满了),不过就是tb1的行数。因此两种方式对于tb2的全表扫描的次数对比为:tb1需要分的次数 vs tb1的行数,差距是非常大的。
由此可知如果被驱动表condition的字段没有索引的话,会有很大的开销,因此如果在数据量较大的情况下一定要要确保被驱动表中加上索引。
参考
- https://www.w3schools.com/sql/sql_join.asp
- https://pdai.tech/md/dev-spec/code-style/code-style-alibaba.html
- 极客时间MySQL实战45讲,第34、35节