我看了这篇文章对于笛卡尔积的认识更深入了,感觉sql语句的执行过程和算法分析中的分析时间复杂度的过程很像。因此特意转载一下,感谢写作本文的大神。
select * from a
where id in(select id from b)
以上查询使用了in语句,in()只执行一次,它查出b表中的所有id字段并缓存起来.之后,检查a表的id是否与b表中的id相等,如果相等则将a表的记录加入结果集中,直到遍历完a表的所有记录.
它的查询过程类似于以下过程
list resultset=[];
array a=(select * from a);
array b=(select id from b);
for(int i=0;i < a.length;i++) {
for(int j=0;j < b.length;j++) {
if(a[i].id==b[j].id) {
resultset.add(a[i]);
break;
}
}
}
return resultset;
可以看出,当b表数据较大时不适合使用in(),因为它会b表数据全部遍历一次.
如:a表有10000条记录,b表有1000000条记录,那么最多有可能遍历10000*1000000次,效率很差.
再如:a表有10000条记录,b表有100条记录,那么最多有可能遍历10000*100次,遍历次数大大减少,效率大大提升.
结论:in()适合b表比a表数据小的情况
select a.* from a a
where exists(select 1 from b b where a.id=b.id)
以上查询使用了exists语句,exists()会执行a.length次,它并不缓存exists()结果集,因为exists()结果集的内容并不重要,重要的是结果集中是否有记录,如果有则返回true,没有则返回false.
它的查询过程类似于以下过程
list resultset=[];
array a=(select * from a)
for(int i=0;i < a.length;i++) {
if(exists(a[i].id) { //执行select 1 from b b where b.id=a.id是否有记录返回
resultset.add(a[i]);
}
}
return resultset;
当b表比a表数据大时适合使用exists(),因为它没有那么遍历操作,只需要再执行一次查询就行.
如:a表有10000条记录,b表有1000000条记录,那么exists()会执行10000次去判断a表中的id是否与b表中的id相等.
如:a表有10000条记录,b表有100000000条记录,那么exists()还是执行10000次,因为它只执行a.length次,可见b表数据越多,越适合exists()发挥效果.
再如:a表有10000条记录,b表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询,我们都知道查询数据库所消耗的性能更高,而内存比较很快.
结论:exists()适合b表比a表数据大的情况
当a表数据与b表数据一样大时,in与exists效率差不多,可任选一个使用.