in 和 exists 的执行过程

有如下 SQL 查询语句:

select * from t1 where name in (select name from t2);

对于 in

先执行子查询,即上面的内表 t2 ,然后把查询结果与外表 t1 进行笛卡尔积,再通过条件进行筛选(这里的条件就是 name 是否相等),把符合条件的数据加入结果集中

for(y in t2){
    for(x in t1){
    	// name 是否相等
        if(condition is true) {
        	result.add();
        }
    }
}

对于 exists

先遍历查询外表 t1,每次遍历时,再检查内表 t2 是否符合条件

for(x in t1){
    for(y in t2){
    	// name 是否相等
        if(condition is true) {
        	result.add();
        }
    }
}

in 和 exists 是否走索引

对于 in

早期版本 MySQL 的 in 查询确实不会走索引,但是 MySQL 5.5 版本之后做了优化,针对建立了索引的列可能使用索引,没有索引的列依然是全表扫描

注意,上面的用词是“可能”,因为 in 是否真正走索引主要取决于表的数据量

MySQL 出于执行成本和效率的考虑,对于小表,按索引访问实际上比全表扫描的成本更高,此时还是会进行全表扫描

对于 exists

它以外层表为驱动表,无论如何都会全部遍历,所以外表 t1 是全表扫描

而内层表通过走索引,可以快速判断是否符合条件,所以内表 t2 会使用索引

in 和 exists 谁快谁慢

  • 外表大,内表小,in 快
  • 外表小,内表大,exists 快

参考:

https://segmentfault.com/a/1190000023825926

https://juejin.cn/post/6863738121096265741