大家对join应该都不会陌生,join可以将两个表连接起来。
join流程详解
join 是指 将两个表连接起来,两个表分别为 驱动表 和 被驱动表。
我们拿下面的这个sql举例,
select t1.id,t2.id from t1 inner join t2 on t1.id = t2.id where t1.id > 10;
t1和t2 都对 id 建立了索引,我们假设 t1 是驱动表,t2是被驱动表。
join流程如下: 1、MySQL每次从t1中读取一行满足过滤条件t1.id>10的记录,如果有索引的话,就利用索引。如果没有索引的话,就从头到尾遍历。 2、当从t1中读取到一条记录后,就根据连接的条件,也就是 on关键字后的条件,去t2中对应的t2中的记录,将t1的记录和t2的记录组合返回给客户端 3、就这样,依次的读取t1中符合条件的记录,然后查询t2,直到t1中的记录读取完毕
从上述流程可以看出,join的大致过程就是从驱动表中挨个读取符合条件的记录,然后根据连接条件到被驱动表中找出符合条件的记录,将其组合到一起返回给客户端。
驱动表和被驱动表的选择
驱动表和被驱动表的选择关乎到整个join的查询效率,如何正确的选取驱动表和被驱动表呢?
其实MySQL会自动优化,选出合适的驱动表和被驱动表,我们看一下MySQL的选取规则。
1、因为驱动表中的记录需要到被驱动表中查询,被驱动表中关于连接条件的字段最好有索引
2、如果两个表都有连接字段的索引,那么就让小表当驱动表,大表当被驱动表
这里的表的规模不是指的是表的原生规模,而是满足过滤条件后的表的规模,
因为被驱动表可以通过索引查询,相当于只扫描一行记录。
假如现在有两个表t1和t2,t1的记录数为100,t2为1000。
如果t1当驱动表,那么只要扫描100 + 100 = 200; 如果t2当驱动表,那么需要扫描1000 + 1000 = 2000
所以驱动表应该选择小表
3、如果两个表关于连接字段都没有索引,那么MySQL会将驱动表中的数据全部读取到内存中,然后依次读取被驱动表中的记录,将被驱动表中的记录去和内存中的驱动表做比对,如果满足连接条件,就将对应的记录拼接返回。
为什么要将驱动表中的数据读取到内存呢?
因为磁盘IO是个非常低效的操作,所以将对应的驱动表的所有数据都读取到内存中,直接和内存比对。
不然的话,每次比对,还需要每次将驱动表的数据从磁盘中读取出来,效率太低了。
如果内存太小,放不下驱动表的数据呢?那就将驱动表中的数据分为多段依次放到内存中。
将被驱动表中的数据 逐行取出,和内存中的驱动表的一段数据进行比对。
当被驱动表中的数据比对完毕后,就将内存清空,然后将驱动表中的下一段数据取出重新放到内存中,重新比对。
被驱动表的数据要比对多次,虽然比较的次数不变,但是需要多次将驱动表中的数据从磁盘上读取到内存中,这是非常耗时的。
|