exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当exists里的条件语句能够返回记录行时(无论记录行是多少,只要能返回),条件就为真,返回当前loop到的这条记录,反之如果exists里的条件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,当能返回结果集则为true,不能返回结果集则为false
如下:
select * from user where exists(select 1);
对user表的记录逐条取出,由于子条件中的select 1永远能返回记录行,那么user表的所有记录都将被加入结果集,所以与select * from user;是一样的
又如下
select * from user where exists(select * from user where userId = 0);
可以知道对user进行loop时,检查条件语句(select * from user where userId = 0),由于userId永远不为0,所以条件永远为false,那么user表的所有记录都将被丢弃
not exists与exists相反,也就是当exists条件有结果返回时,loop到的记录将被丢弃,否则将loop到的记录加入结果集
总的来说,如果A表有n条记录,那么exists查询就是将这n条数据逐条取出,然后判断n遍exists条件
in查询相当于多个or条件的叠加
如下:
select * from user where userId in (1,2,3);
等效于
select * from user where userId =1 or userId = 2 or userId = 3;
not in与in相反,如下
select * from user where userId not in(1,2,3);
等效于
select * from user where userId !=1 and userId !=2 and userId !=3;
总的来说,in查询就是先将子查询条件的记录全部查出来,假设结果集为B,共有m条记录,然后在将子查询条件结果分解成m个,再进行m次查询
值得一提的是,in查询的子条件返回结果必须只有一个字段,例如
select * from user where userId in(select id from B);
而不能是
select * from user where userId in(select id,age from B);
而exists就没有这个限制
下面来考虑exists和in的性能
如下:
1,select * from A where exists (select * from B where B.id = A.id)
2,select * from A where A.id in(select id from B);
查询1转化为伪代码:
for($i=0;$i<count(A);$i++){
$a = get_record(A,$i);//从A表逐条获取记录
if(B.id = $a['id']){//如果子条件成立
$result[] = $a;
}
}
return $result;
可以看到,查询1主要用到的是B表的索引,A表如何对查询的效率影响应该不大
假设B表的所有id为1,2,3,产寻2可以转化为
select * from A where A.id = 1 or A.id = 2 or A.id = 3;
这里主要用到了A的索引,B表如何对查询影响不大
再看not exists和not in
1,select * from A where not exists (select * from B where B.id = A.id);
2,select * from A where A.id not in(select id from B);
查询1,还是用了B的索引
查询2,可以转换为
select * from A where A.id !=1 and A.id !=2 and A.id != 3;
可以知道not in是个范围查询,这种!=的范围查询无法使用任何索引,等于说B表的每条记录,都要在A表里遍历一次,查看A表里是存在这条记录
故not exists比not in效率高
如果查询的两个表大小相当,那么用in和exists差别不大
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:
例如:表A(小表),表B(大表)
1:
select * from A where cc in(select cc from B)效率低,用到了A表上的cc列索引;
select * from A where exists(select cc from B where cc=A.cc)效率高,用到了B表上的cc列索引
2:
select * from B where cc in(select cc from A)效率高,用到了B表上cc列索引
select * from B where exists(select cc from A where cc=B.cc)效率低,用到了A表上cc列索引
not in和not exists
如果查询语句使用了not in那么内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引
所以无论那个表大,not exists都比not in要快
in与=的区别
select name from student where name in('zhang','wang','li');
与
select name from student where name='zhang' or name='li' or name='wang';
的结果是相同