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 快
参考:
- Post link: http://example.com/2022/02/14/MySQL%E4%B8%ADin%E5%92%8Cexists%E6%89%A7%E8%A1%8C%E6%95%88%E7%8E%87%E7%9A%84%E5%88%86%E6%9E%90/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.